首页 > 编程语言 >JAVA反射

JAVA反射

时间:2024-11-05 21:22:41浏览次数:3  
标签:反射 JAVA System clazz 获取 println Class out

反射

java.lang.Class类

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect.*。所以,Class对象是反射的根源。

获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

public class TestClass {
	@Test
	public void test05() throws ClassNotFoundException{
		Class c = TestClass.class;
		ClassLoader loader = c.getClassLoader();
		
		Class c2 = loader.loadClass("com.atguigu.test05.Employee");
		Class c3 = Employee.class;
		System.out.println(c2 == c3);
	}
	
	@Test
	public void test03() throws ClassNotFoundException{
		Class c2 = String.class;
		Class c1 = "".getClass();
		Class c3 = Class.forName("java.lang.String");
		
		System.out.println(c1 == c2);
		System.out.println(c1 == c3);
	}
}

反射的应用

获取类的详细信息

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

获取类的:包、修饰符、全类名、父类、实现的接口名

public class TestClassInfo {
	public static void main(String[] args) throws NoSuchFieldException, SecurityException {
		//1、先得到某个类型的Class对象
		Class clazz = String.class;
		//比喻clazz好比是镜子中的影子
		
		//2、获取类信息
		//(1)获取包对象,即所有java的包,都是Package的对象
		Package pkg = clazz.getPackage();
		System.out.println("包名:" + pkg.getName());
		
		//(2)获取修饰符
		//其实修饰符是Modifier,里面有很多常量值
		/*
		 * 0x是十六进制
		 * PUBLIC           = 0x00000001;  1    1
		 * PRIVATE          = 0x00000002;  2	10
		 * PROTECTED        = 0x00000004;  4	100
		 * STATIC           = 0x00000008;  8	1000
		 * FINAL            = 0x00000010;  16	10000
		 * ...
		 * 
		 * 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
		 * 
		 * mod = 17          0x00000011
		 * if ((mod & PUBLIC) != 0)  说明修饰符中有public
		 * if ((mod & FINAL) != 0)   说明修饰符中有final
		 */
		int mod = clazz.getModifiers();
		System.out.println(Modifier.toString(mod));
		
		//(3)全类名
		String name = clazz.getName();
		System.out.println(name);
		
		//(4)父类,父类也有父类对应的Class对象
		Class superclass = clazz.getSuperclass();
		System.out.println(superclass);
		
		//(5)父接口们
		Class[] interfaces = clazz.getInterfaces();
		for (Class class1 : interfaces) {
			System.out.println(class1);
}

注解(类上的、方法上的、属性上的)

//获取类上的注解
//假设有一个类 MyClass,我们在其上定义了一个注解 @MyAnnotation。
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  

@Retention(RetentionPolicy.RUNTIME)  
@interface MyAnnotation {  
    String value() default "class annotation";  
}  

@MyAnnotation("This is a class annotation")  
class MyClass {  
    // 类体  
}  
//获取类上的注解:
public class AnnotationExample {  
    public static void main(String[] args) {  
        Class<MyClass> clazz = MyClass.class;  
        MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);  
        
        if (annotation != null) {  
            System.out.println("Class Annotation: " + annotation.value());  
        }  
    }  
} 



//判断一个类、方法或属性上是否存在特定的注解
//判断类上的注解
//假设我们有一个自定义注解 @MyAnnotation,并在一个类上使用它:
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  

@Retention(RetentionPolicy.RUNTIME)  
@interface MyAnnotation {  
    String value() default "class annotation";  
}  

@MyAnnotation("This is a class annotation")  
class MyClass {  
    // 类体  
}  
//判断类上是否存在该注解:
public class AnnotationCheck {  
    public static void main(String[] args) {  
        Class<MyClass> clazz = MyClass.class;  

        // 判断类上是否存在 MyAnnotation 注解  
        if (clazz.isAnnotationPresent(MyAnnotation.class)) {  
            System.out.println("MyClass has MyAnnotation.");  
        } else {  
            System.out.println("MyClass does not have MyAnnotation.");  
        }  
    }  
}  

获取类的成员(属性、构造器、方法)

//(1)类的属性,  你声明的一个属性,它是Field的对象

	/*	Field clazz.getField("name")  根据属性名获取一个属性对象,但是只能得到公共的
		Field[] clazz.getFields();  获取所有公共的属性[会获取到父类的公共属性]
		Field clazz.getDeclaredField("name")  根据属性名获取一个属性对象[任何类型]
		Field[] clazz.getDeclaredFields()	获取所有已声明的属性[包括私有属性,不会获取到父类属性]
		*/

 		//根据属性名获取一个属性对象,但是只能得到公共的[可以获取到父类的公共属性]
        Field field = studentClass.getField("name");
        System.out.println("field = " + field);

        //获取所有公共的属性[会获取到父类的公共属性]
        Field[] fields = studentClass.getFields();
        for (Field field : fields) {
            System.out.println("field = " + field);
        }
		//根据属性名获取一个属性对象,可以获取已声明的[包括私有属性,不包括父类属性]
		Field valueField = clazz.getDeclaredField("value");
		System.out.println("valueField = " + field);

		//获取所有已声明的属性[包括私有属性,不包括父类属性]
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			System.out.println("field = " + field);
		}
        //获取父类的所有属性:首先获取父类对象 getSuperclass();然后通过父类对象获取所有属性
        Class<? super Student> superclass = studentClass.getSuperclass();

    	Field[] declaredFields1 = superclass.getDeclaredFields();
        for (Field field : declaredFields1) {
            System.out.println("field = " + field1);
        }

//(2)构造器
	/*	
		获取公共无参构造器对象[只能public]
		Constructor clazz.getConstructor(); 
		
		获取所有公共的构造器对象[不会获取到父类构造器]
		Constructor<?>[] clazz.getConstructors();  
		
		获取无参构造器对象[任何类型(public、protected、default、private)]
	    Constructor clazz.getDeclaredConstructor(); 
	    
	    获取所有构造器对象[任何类型(public、protected、default、private),不会获取到父类构造器]
		Constructor<?>[] clazz.getDeclaredConstructors();	
		
		无参构造器(参数表里写上参数)就是获取有参构造器***
		clazz.getDeclaredConstructor(参数表)
	*/

		//获取无参构造器对象
  		Constructor<Student> constructor = studentClass.getConstructor();

		//获取所有公共的构造器[不会获取到父类构造器]
		 Constructor<?>[] constructors = studentClass.getConstructors();

		////获取无参构造器对象
		Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor();

		//获取所有构造器对象[不会获取到父类构造器]
		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
		for (Constructor constructor : constructors) {
			//获取构造器的修饰符、构造器名称、构造器形参列表  、抛出的异常列表
			int modifiers = constructor.getModifiers();
			System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
			
			String name = constructor.getName();
			System.out.println("构造器名:" + name);
			
			//形参列表
			System.out.println("形参列表:");
			Class[] parameterTypes = constructor.getParameterTypes();
			for (Class parameterType : parameterTypes) {
				System.out.println(parameterType);
			}
            
            //异常列表
			System.out.println("异常列表:");
			Class<?>[] exceptionTypes = constructor.getExceptionTypes();
			for (Class<?> exceptionType : exceptionTypes) {
				System.out.println(exceptionType);
			}
		}


//(3)方法们
		/*	
		根据方法名获取一个方法对象,但是只能得到公共的
		Method clazz.getMethod("name"); 
		
		获取所有公共的方法对象[会获取到父类方法]
		Method[] clazz.getMethods();  
		
		根据方法名获取一个方法对象[任何类型(public、protected、default、private)]
	    Method clazz.getDeclaredMethod("name"); 
	    
	    获取所有方法对象[任何类型(public、protected、default、private),不会获取到父类方法]
		Method[] clazz.getDeclaredMethods();	
		*/
		//根据方法名获取一个方法对象,但是只能得到公共的
 		Method method = studentClass.getMethod("study");
      	
		//获取所有公共的方法对象[会获取到父类方法]
        Method[] methods = studentClass.getMethods();
        
		//根据方法名获取一个方法对象[任何类型(public、protected、default、private)]
		Method declaredMethod = studentClass.getDeclaredMethod("sleep");

		//获取所有方法对象[任何类型(public、protected、default、private),不会获取到父类方法]
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			//获取方法的修饰符、返回值类型、方法名、形参列表 、异常列表 
			int modifiers = method.getModifiers();
			System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
			
			Class<?> returnType = method.getReturnType();
			System.out.println("返回值类型:" + returnType);
			
			String name2 = method.getName();
			System.out.println("方法名:" + name2);
			
			//形参列表
			System.out.println("形参列表:");
			Class[] parameterTypes = method.getParameterTypes();
			for (Class parameterType : parameterTypes) {
				System.out.println(parameterType);
			}
			
			//异常列表
			System.out.println("异常列表:");
			Class<?>[] exceptionTypes = method.getExceptionTypes();
			for (Class<?> exceptionType : exceptionTypes) {
				System.out.println(exceptionType);
			}
		}

创建任意引用类型的对象并赋值(调构造器赋值)

两种方式:

  • 1、直接通过Class对象来实例化(要求必须有无参构造)
  • 2、通过获取构造器对象来进行实例化

方式一的步骤:

(1)获取该类型的Class对象(2)创建对象

如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

	@Test
	public void test2()throws Exception{
		Class<?> clazz = Class.forName("com.chs.test.Student");
		//Caused by: java.lang.NoSuchMethodException: com.chs.test.Student.<init>()
		//即说明Student没有无参构造,就没有无参实例初始化方法<init>
		Object stu = clazz.newInstance();
		System.out.println(stu);
	}
	
	@Test
	public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
        //Student obj = new Student();//编译期间无法创建
		
		Class<?> clazz = Class.forName("com.chs.test.Student");
		//clazz代表com.chs.test.Student类型
		//clazz.newInstance()创建的就是Student的对象
		Object obj = clazz.newInstance();
		System.out.println(obj);
	}

方式二的步骤:

(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象

如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

示例代码:

public class TestNewInstance {
	@Test
	public void test3()throws Exception{
		//(1)获取Class对象
		Class<?> clazz = Class.forName("com.chs.test.Student");
		/*
		 * 获取Student类型中的有参构造
		 * 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
		 * 例如:public Student(int id, String name) 
		 */
		//(2)获取构造器对象
	   Constructor<?> constructor = clazz.getDeclaredConstructor(int.class,String.class);
		
		//(3)创建实例对象
		// T newInstance(Object... initargs)  这个Object...是在创建对象时,给有参构造的实参列表
		Object obj = constructor.newInstance(2,"张三");
		System.out.println(obj);
}
    
    //访问私有构造器
    @Test
    public void test05() throws Exception{
        //1.获取Class 对象
        Class<Person> personClass = Person.class;
        //2.获取指定的构造器
        Constructor<Person> c = personClass.getDeclaredConstructor(String.class, int.class, double.class);
        //3.禁止java语言的权限访问检测
        c.setAccessible(true);
        //4.给成员变量赋值
        Person person = c.newInstance("王安石", 30, 9898.6);
        //5.展示结果
        System.out.println("person = " + person);
    }
}

操作任意类型的属性

(1)获取该类型的Class对象
Class clazz = Class.forName("com.chs.bean.User");

(2)获取属性对象
Field field = clazz.getDeclaredField("username");

(3)设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();

(5)设置属性值

field.set(obj,"chai");
(6)获取属性值
Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

(5)设置属性值

field.set(null,"chai");
(6)获取属性值
Object value = field.get(null);

示例代码:

//操作静态变量 	
@Test
public void test01() throws NoSuchFieldException, IllegalAccessException {
        //1.获取Class对象
        Class<Monkey> monkeyClass = Monkey.class;
        //2.获取指定的属性
        Field message = monkeyClass.getDeclaredField("message");
        //3.设置私有的属性可以操作
        message.setAccessible(true);
        //4.给属性赋值
        message.set(null,"HelloWorld");
        //5.获取属性值
        Object value = message.get(null);
        System.out.println("value = " + value);
}
//操作普通变量 	
@Test
public void test02() throws Exception {
       //1.获取Class对象
        Class<Monkey> monkeyClass = Monkey.class;
        //2.获取指定的属性
        Field gender = monkeyClass.getDeclaredField("gender");
        //todo 设置私有的属性可以访问
        gender.setAccessible(true);
        //3.创建对象
        Monkey monkey = monkeyClass.newInstance();
        System.out.println("monkey = " + monkey);
        //4.给属性赋值
        //todo 给monkey 对象的gender 属性赋值 为 男
        gender.set(monkey,'男');
        //5.展示对象
        System.out.println("monkey = " + monkey);
}

调用任意类型的方法

(1)获取该类型的Class对象
Class clazz = Class.forName("com.chs.service.UserService");
(2)获取方法对象
Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,"chai","123);

如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

method .setAccessible(true);

如果方法是静态方法,实例对象也可以省略,用null代替

Object result = method.invoke(null,"chai","123);

示例代码:

//操作静态方法  
@Test
    public void test04() throws Exception{
       //todo 私有的静态方法
        //1.获取Class对象
        Class<Animal> animalClass = Animal.class;
        //2.获取指定的方法
        Method isPrimeNum = animalClass.getDeclaredMethod("isPrimeNum", int.class);
        //3.设置私有方法可以使用
        isPrimeNum.setAccessible(true);
        //4.执行方法 获取结果
        Object invoke = isPrimeNum.invoke(null, 20);
        //5.输出结果
        System.out.println("invoke = " + invoke);

    }
//操作普通方法 
    @Test
    public void test03() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
       //todo 公共的实例方法
        //1.获取Class对象
        Class<Animal> aClass = Animal.class;
        //2.获取指定的方法
        Method sum = aClass.getMethod("sum", int.class, int.class);
        //3.创建对象
        Animal animal = aClass.newInstance();
        //4.调用方法
        sum.invoke(animal,89,20);

    }

标签:反射,JAVA,System,clazz,获取,println,Class,out
From: https://www.cnblogs.com/21CHS/p/18528875

相关文章

  • C语言字符数组 java封装
    1.intmain(void){   inta[5]={1,3,5,7,9};   charstrl[5]={'A','B','C','D','E'};   charstr2[5]="ABCD";//不能是ABCDE,最后还有\0   inti=0;   //for(i=0;i<5;i++)   //{ ......
  • 零基础学习Spring AI Java AI使用向量数据库postgresql 检索增强生成 RAG
    零基础学习SpringAIJavaAI使用向量数据库postgresql检索增强生成RAG向量数据库是一种特殊类型的数据库,在人工智能应用中发挥着至关重要的作用。在向量数据库中,查询与传统的关系数据库不同。它们不是进行精确匹配,而是执行相似性搜索。当给定一个向量作为查询时,向量数......
  • javascript跨域问题排查
    什么是跨域问题跨域是指浏览器从一个域名的网页去请求另一个域名下的资源。出于安全考虑,浏览器会限制这种跨域请求。例如,网页http://example1.com中的JavaScript代码尝试去获取http://example2.com的数据,这就会触发跨域问题。同源策略规定,只有当协议(如http、https)、域名(如ex......
  • Javascript 代码规范
    JavaScript代码规范是编程时遵循的一套规则和最佳实践,以确保代码的可读性、可维护性和一致性。以下是一些关键的JavaScript常见代码规范:1.使用严格模式在所有脚本文件或函数开头添加‘usestrict’;声明,以启用严格模式(strictmode),这有助于捕获潜在的错误并避免不明......
  • Java内存区域详解(重点)
    运行时数据区域Java虚拟机在执行Java程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK1.8和之前的版本略有不同,我们这里以JDK1.7和JDK1.8这两个版本为例介绍。JDK1.7:JDK1.8: 线程私有的:程序计数器虚拟机栈本地方法栈线程共享的:堆方法区......
  • java计算机毕业设计基于springboot的小区物业管理系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、研究背景随着城市化进程的加速,小区规模不断扩大,小区物业管理面临着诸多挑战。传统的物业管理方式依赖人工操作,效率低下,容易出现信息管理混乱、服务响应不......
  • java计算机毕业设计在线考试(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、研究背景随着信息技术的迅猛发展,互联网在教育领域的渗透日益加深。在线教育成为一种广泛应用的教育模式,与之相伴的在线考试也逐渐兴起。传统考试存在诸多......
  • 【Java猿猿必备】Hutool工具库开箱即用
            Hutool真心是一个不错的国产Java工具类库,功能全面,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行了封装,开箱即用!深受国内开发者的喜爱。目前确实是成为了国内使用最广的工具库之一了,Gitee上的Star数也到了23k+。项目地址:https://git......
  • Java入门十二——static详解(含toString)
    上节课,我们只是微微提到了static,今天我们来具体讲讲static的用法static1.类名.静态成员变量(上篇博客Java入门十一有讲)为了方便大家查看,我把链接放在这里Java入门11——关键字总结+static-CSDN博客2.类名.静态成员方法这里,我们首先创建两个类,分别是java12和demo1,然后调用d......
  • 什么是java序列化?什么情况下需要序列化?
      序列化的定义Java序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。序列化是一种用于处理对象流的机制,它将对象的内容转换成一种可以在网络之间传输的形式。反序列化则是将这种形式的对象恢复成原来的对象。实现方式序列化是通过实现​​Seri......