Java中的反射机制——动态编程
参考:
https://github.com/JustinSDK/JavaSE6Tutorial/blob/master/docs/CH16.md
《Java编程思想》
反射的作用
能够在运行时获取类的信息(而不是编译时),使java语言在运行时拥有一项“自观”的能力。
具体来说:
- 在运行时判断任意对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时操作对象(操作方法,改变字段值(无所谓公有私有))。
通常是通过一个类创建对象,而反射方法就是通过一个对象找到一个类的信息。
可以参考一个实例:http://blog.csdn.net/ljphhj/article/details/12858767
判断对象所属的类
<1>Class object.getClass();
<2>Class 类.class;
<3>Class Class.forName(String className)//className必须是包含package的全名
均可以返回一个Class引用对象。这是在运行时获取各种类型信息的前提。
介绍几个Class对象常用的几个方法:
public class LocalTest {
public static void main(String[] args) {
try {
Class c = Class.forName("Models.Person.Enermy");
System.out.println("类别名称:"+c.getName());
System.out.println("父类为:" + c.getSuperclass());
System.out.println("是否为接口:" + c.isInterface());
System.out.println("是否为基本类型:" + c.isPrimitive());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}/*Output
类别名称:Models.Person.Enermy
父类为:class Models.Person.Person
是否为接口:false
是否为基本类型:false*/
构造类的对象
Class c = ...;
Object obj = c.newInstance();
可以对obj发送除Object之外的任何消息,前提是更多地了解obj并对其执行某种转型(instanceof)。
另外,使用newInstance()创建的类,必须带有默认的构造器。
当然还可以用其他反射API,用任意的构造器来动态地创建类的对象(Constructors).
获取类的成员变量和方法
得到构造器
Constructor[] getConstructors() //获得类的所有公共构造函数 Constructor[] getDeclaredConstructors() //获得类的所有构造函数
得到成员变量
Field[] getFields() //获得类的公有字段 Field[] getDeclaredFields() //获得类的所有字段
得到方法
Method[] getMethods() //获得类的所有公有方法 Method[] getDeclaredMethods() //获得类的所有方法
操作对象
与JavaBean息息相关(各种setter与getter). 示例如下:
执行方法:
Method method = obj.getClass().getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(obj);
修改字段:
Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.setInt(obj,20);
详见invoke的使用。
instanceOf和equals
当检查两个对象是否相等时,instanceof和isInstance()生成的结果完全一样,equals和==的结果也一样,但这两组测试的结果却不同。
public class LocalTest {
public static void main(String[] args) {
Person person = PersonFactory.create("Models.Person.Enermy");//Enermy extends Person
System.out.println(person.getClass().getName());
//instanceof
System.out.println(person instanceof Person);
//isInstance
System.out.println(Person.class.isInstance(person));
//equals
System.out.println(person.getClass().equals(Person.class));
//==
System.out.println(person.getClass() == Person.class);
}
}
运行结果:
Models.Person.Enermy
true
true
false
false
instanceof保持了类型的概念,它指的是“你是这个类吗?你是这个类的派生类吗?”,如果用equals比较对象,就没有考虑继承——它或者是这个确切的类型,或者不是。
动态代理
代理是一种基本的设计模式,由代理对象控制原对象的引用,可以将额外的操作从“真实”对象中分离到不同的地方,并可以保护“真实”对象的访问权限。
静态代理:为确定的“真实”对象创建专用的代理。
动态代理:在运行期动态地创建代理并动态地处理对所代理方法的调用。
动态代理的使用步骤:
(1)创建动态代理
可以通过使用 Proxy.newProxyInstance()方法创建动态代理。
InvocationHandler handler = new MyInvocationHandler(new RealObject());
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class },
handler);
newProxyInstance()方法有三个参数:
- 类加载器(ClassLoader)用来加载动态代理类。
- 一个要实现的接口数组。
- InvocationHandler接口的一个实现。
(2)实现自己的InvocationHandler接口
public class MyInvocationHandler implements InvocationHandler{
private Object proxied;
public MyInvocationHandler(Object proxied){
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//do something "dynamic"
}
}
- proxy参数是实现要代理接口的动态代理对象。通常你是不需要使用它的。
- invoke()方法中的 Method 对象参数代表了被动态代理的接口中要调用的方法,从这个 method 对象中你可以获取到这个方法名字,方法的参数,参数类型等等信息。
- Object数组参数包含了被动态代理的方法需要的方法参数。