Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
在编译后产生字节码文件的时候,类加载器子系统通过二进制字节流,负责从文件系统加载class文件。
在执行程序(java.exe)时候,将字节码文件读入JVM中--->这个过程叫做类的加载。然后在内存中对应创建一个java.lang.Class对象-->这个对象会被放入字节码信息中,这个Class对象,就对应加载那个字节码信息,这个对象将被作为程序访问方法区中的这个类的各种数据的外部接口。
所以:我们可以通过这个对象看到类的结构,这个对象就好像是一面镜子,透过镜子看到类的各种信息,我们形象的称之为反射
这种“看透”class的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
说明:在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。
如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。
获取字节码的的四种形式:
- //方式1:通过getClass()方法获取
- Person p = new Person();
- Class c1 = p.getClass();
- System.out.println(c1);
- //方式2:通过内置class属性:
- Class c2 = Person.class;
- System.out.println(c2);
- System.out.println(c1==c2); true
- //注意:方式1和方式2 不常用
- //方式3:--》用的最多:调用Class类提供的静态方法forName
- Class c3 = Class.forName("com.zhaoss.test02.Person");
- //方式4:利用类的加载器(了解,不常用)
- ClassLoader loader = Test.class.getClassLoader();
- Class c4 = loader.loadClass("com.zhaoss.test02.Person");
获取运行时类的信息:
获取构造器
- //通过字节码信息可以获取构造器:
- //getConstructors只能获取当前运行时类的被public修饰的构造器
- Constructor[] c1 = cls.getConstructors();
- //getDeclaredConstructors:获取运行时类的全部修饰符的构造器
- Constructor[] c2 = cls.getDeclaredConstructors();
- //获取指定的构造器:
- //得到空构造器
- Constructor con1 = cls.getConstructor();
- //有了构造器以后我就可以创建对象:
- Object o1 = con1.newInstance();
获取属性
- //getFields:获取运行时类和父类中被public修饰的属性
- Field[] fields = cls.getFields();
- //getDeclaredFields:获取运行时类中的所有属性
- Field[] declaredFields = cls.getDeclaredFields();
- //获取指定的属性:
- Field score = cls.getField("属性名称");
- //给属性赋值:(给属性设置值,必须要有对象)
- Field sco = cls.getField("score");
- Object obj = cls.newInstance();
- //给obj这个对象的score属性设置具体的值,这个值为98
- sco.set(obj,98);
获取方法
- //getMethods:获取运行时类的方法还有所有父类中的方法(被public修饰)
- Method[] methods = cls.getMethods();
- //getDeclaredMethods:获取运行时类中的所有方法:
- Method[] declaredMethods = cls.getDeclaredMethods();
- //获取指定的方法:
- Method showInfo1 = cls.getMethod("方法名称");
- //调用方法:
- Object o = cls.newInstance();
- //调用o对象的mymethod方法
- myMethod.invoke(o);
获取接口
- //获取运行时类的接口:
- Class[] interfaces = cls.getInterfaces();
- //得到父类的接口:
- //先得到父类的字节码信息:
- Class superclass = cls.getSuperclass();
- //得到父类接口:
- Class[] interfaces1 = superclass.getInterfaces();
- //获取运行时类所在的包:
- Package aPackage = cls.getPackage();
- //获取运行类的注解:
- Annotation[] annotations = cls.getAnnotations();