使用反射实例对象
使用反射机制,我们可以在运行时动态加载类并且实例化对象,操作对象的方法、改变类成员的值,甚至还可以改变私有(private)成员的值。
我们可以用 Class 的 newInstance() 方法来实例化一个对象,实例化的对象是以 Object 传回的,例如:1
2Class c = Class.forName(className);
Object obj = c.newInstance();
下面范例动态加载list接口的类:
1 | package CoreJava.day_2; |
输出:
1 | java CoreJava.day_2.NewInstanceDemo java.util.ArrayList |
实际上如果想要使用反射来动态加载类,通常是对对象的接口或类别都一无所知,也就无法像上面对 newInstance() 传回的对象进行接口转换。
如果加载的类中具备无参数的构造方法,则可以无参数的 newInstance() 来构造一个不指定初始化的引用,如果要在动态加载及生成对象时指定对象的引用,则要先指定参数类型、取得 Constructor 对象、使用 Constructor 的 newInstance() 并指定参数。
可以用一个例子来说明,先定义一个student类:
1 | package CoreJava.day_2; |
我们可以用 Class.forName() 来加载 Student ,并使用第二个有参数的构造方法来构造Student 实例:
1 | package CoreJava.day_2; |
输出:
1 | java NewInstanceDemo2 CoreJava.day_2.Student |
调用方法
使用反射可以取回类上方法的对象代表,方法的物件代表是 java.lang.reflect.Method 的实例,我们可以使用它的 invoke() 方法来动态调用指定的方法,例如调用上面 Student 上的 setName() 等方法:
1 | package CoreJava.day_2; |
我们可以指定加载 Student 类并生成实例,接着可以动态调用 setName() 和 setScore() 方法,由于调用setName() 和 setScore() 所设置的参数是 “caterpillar” 和90。
在很少的情況下,我们需要突破 Java 的存取限制来调用受保护的(protected)或私有(private)的方法(例如我们拿到一个组件(Component),但我们没法修改它的原始码来改变某个私有方法的权限,而我们又一定要调用某个私有方法),这时我们可以使用反射机制來达到目的,一个存取私有方法的例子如下:
1 | Method privateMethod = |
使用反射来动态调用方法的实例例子之一是在 JavaBean 的设定,例如在 JSP/Servlet 中,可以根据使用者的请求名和 JavaBean 的属性自动对比,将请求值设置到指定的 JavaBean 上,并自动根据参数类型转换。
下面是一个map的小例子:
1 | package CoreJava.day_2; |
CommandUtil 可以自动根据方法上的参数类型,将Map 中的value转换成相应的类型,目前它可以转换基本类型和 String。
输出:
1 | java CommandUtilDemo CoreJava.day_2.Student |
当然也可以修改成员变量,尽管直接读取类的成员属性(Field)是不被鼓励的,但我们仍是可以直接存取公共的(public)成员属性的,而我们甚至也可以通过反射机制来读取私用成员变量,以一个例子来说明:
1 | package CoreJava.day_2; |
然后利用反射机制动态的读取成员变量:
1 | package CoreJava.day_2; |
输出:
1 | java AssignFieldDemo CoreJava.day_2.TestField |
如果有必要的话,也可以通过反射机制来读取私有的成员变量,例如:
1 | Field privateField = c.getDeclaredField("privateField"); |
数组
在 Java 中数组也是一个对象,也会有一个 Class 实例来表示它,我们用几个基本类型和String来进行测试:
1 | package CoreJava.day_2; |
输出:
1 | short 数组:class [S |
要使用反射机制动态生成数组的话,也可以这样:
1 | package CoreJava.day_2; |
Array.newInstance() 的第一个参数是指定参数类型,而第二个参数是用来指定数组长度的,结果如下:
1 | 0 1 2 3 4 |
如果是二维数组,也是一样的:
1 | package CoreJava.day_2; |
输出结果:
1 | 1 2 3 4 |
如果想要知道数组元素的类型,可以在取得数组的 Class 实例之后,使用 Class 实例的 getComponentType() 方法,所取回的是元素的 Class 实例,例如:
1 | int[] iArr = new int[5]; |
对反射的总结差不多就写到这里了,查阅了很多资料,网络上写的也是参差不齐的,在手写的几十个demo支撑下,得出的一点关于反射的东西,肯定不能说全部正确,但是还是可以提供一些帮助的 -。-