1、概述
JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法
对于任意一个对象,都能够调用它的任意一个方法和属性
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
动态获取类中信息,就是java反射 。可以理解为对类的解剖。
要想要对字节码文件进行解剖,必须要有字节码文件对象,如何获取字节码文件对象呢?
2、获取字节码对象的方式
1、Object类中的getClass()方法的。想要用这种方式,必须要明确具体的类,并创建对象(麻烦)。
String str = new String(); Class clazz = str.getClass(); String str1 = new String(); Class clazz1 = str1.getClass(); System.out.println(clazz == clazz1); //true
2、任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。相对简单,但是还是要明确用到类中的静态成员(还是不够扩展)。
Class clazz = String.class; Class clazz1 = String.class; System.out.println(clazz == clazz1); // true
3、只要通过给定的类的 字符串名称就可以获取该类,更为扩展。可是用Class类中的方法完成。该方法就是forName。这种方式只要有名称即可,更为方便,扩展性更强。
String className = "cn.itcast.bean.Person"; Class clazz = Class.forName(className); System.out.println(clazz);
3、早期创建对象和反射创建对象流程的区别
早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象。
反射:根据类名称找寻该名称类文件,并加载进内存,并产生Class对象,通过newInstance创建对象。
String name = "cn.itcast.bean.Person"; Class clazz = Class.forName(name); Object obj = clazz.newInstance();
当获取指定名称对应类中的所体现的对象时,而该对象初始化不使用空参数构造该怎么办呢?既然是通过指定的构造函数进行对象的初始化,所以应该先获取到该构造函数。通过字节码文件对象即可完成。该方法是:getConstructor(paramterTypes);
String name = "cn.itcast.bean.Person"; Class clazz = Class.forName(name); //获取到了指定的构造函数对象。 Constructor constructor = clazz.getConstructor(String.class,int.class); //通过该构造器对象的newInstance方法进行对象的初始化。 Object obj = constructor.newInstance("小明", 38);
4、获取字节码文件中的字段
获取类中所有的字段或指定字段对象(只获取pulic的字段)
Class<String> clazz = String.class; Field[] fields = clazz.getFields(); // 因为value是私有字段,所以获取时会抛NoSuchFieldException异常 Field field = clazz.getField("value");
获取所有的字段(可包含private)
Class<String> clazz = String.class; Field[] fields = clazz.getDeclaredFields(); Field field = clazz.getDeclaredField("value");
给对象的字段赋值
Class<String> clazz = String.class; Object obj = clazz.newInstance(); Field field = clazz.getDeclaredField("value"); char[] value = { '2', '3' }; // 将value的值赋为23,此时会报错,因为value是私有的 field.set(obj, value); // 暴力对私有字段的访问取消权限检查,此时就可以正常赋值了 field.setAccessible(true); field.set(obj, value);
5、操作Class中的函数
获取Method对象
Class<String> clazz = String.class; // 获取的都是公有的方法。 Method[] methods1 = clazz.getMethods(); // 只获取本类中所有方法,包含私有。 Method[] methods2 = clazz.getDeclaredMethods(); // 根据名称获取指定方法(空参) Method method = clazz.getMethod("show", null); // 方法是私有的话会抛NoSuchMethodException异常 // Method method = clazz.getDeclaredMethod("show", null); // 根据名称获取指定方法(带参) Method method = clazz.getMethod("paramMethod", String.class, int.class);
方法的调用
Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("paramMethod", String.class,int.class); Object obj = clazz.newInstance(); method.invoke(obj, "小强",89); // 空参函数的调用:method.invoke(obj, null);