在过去的几次面试中,都被问到了反射这块的知识,并没有系统了解过Java的反射机制(现实是几乎怎么接触过),所以这方面的问题基本都回答不上来T_T
镇定思痛,我们来一起好好看看Java中反射的用法。
关于反射的基本用法, http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html 已经有了比较全面的总结,例子也比较丰富,但是有些地方讲的也不太对,而且对于内部类的反射并没有讲到。
在获取多个构造器并用这个构造器创建新实例时用了这样的例子:
package Reflect;
import java.lang.reflect.Constructor;
class Person{
public Person() {
}
public Person(String name){
this.name=name;
}
public Person(int age){
this.age=age;
}
public Person(String name, int age) {
this.age=age;
this.name=name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Person per1=null;
Person per2=null;
Person per3=null;
Person per4=null;
//取得全部的构造函数
Constructor<?> cons[]=demo.getConstructors();
try{
per1=(Person)cons[0].newInstance();
per2=(Person)cons[1].newInstance("Rollen");
per3=(Person)cons[2].newInstance(20);
per4=(Person)cons[3].newInstance("Rollen",20);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
然而我运行这个程序会得到一个Exception:
这是由于获取到的构造器的顺序和原来类中定义的顺序不一样造成的。
在我的机器上,必须按照如下构造器的顺序才能正常新建实例:
在查阅了一些资料后我了解到JDK对于这个顺序并没有作要求,使用不同版本的JDK获取的构造器顺序可能会有不同,我们写程序的时候不应该依赖这个顺序。
正确的做法是在Class上调用带参数列表的getConstructor()方法来获取对应的Constructor,再使用这个Constructor来生成新实例。
例如:
Constructor cons0 = demo.getConstructor();
Constructor cons1 = demo.getConstructor(String.class);
Constructor cons2 = demo.getConstructor(int.class);
Constructor cons3 = demo.getConstructor(String.class,int.class);
Person per1 = (Person) cons0.newInstance();
Person per2 = (Person) cons1.newInstance("Rollen");
Person per3 = (Person) cons2.newInstance(20);
Person per4 = (Person) cons3.newInstance("Rollen", 20);
最后是获取内部类私有成员变量和方法的例子:
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class InnerClassTest {
public InnerClassTest() {
}
public InnerClassTest(String str) {
}
class Inner {
private String name = "Inner";
public Inner() {
}
public Inner(String na) {
name = na;
}
private int get(int value){
return value;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "InnerClass : " + name;
}
}
public static void main(String args[]) {
try {
Class c = Class.forName("Reflect.InnerClassTest$Inner");
if (c != null) {
Constructor con = c.getDeclaredConstructor(InnerClassTest.class,String.class);
System.out.println(con.newInstance(new InnerClassTest(),"hello"));
Method me = c.getDeclaredMethod("get",int.class);
me.setAccessible(true);
System.out.println(me.invoke(new InnerClassTest().new Inner(),20));
Field fe = c.getDeclaredField("name");
fe.setAccessible(true);
System.out.println(fe.get(new InnerClassTest().new Inner()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(非静态的)内部类的构造方法获取时比较不一样,需要传入外部类对象,同时,在通过获取的构造器创建实例的时候也需要传入外部类的实例。
对于静态的对象和方法,对其调用get()或者invoke()方法时第一个参数将会被忽略,我们直接传入空对象null就可以了。