Java 中反射机制的深入研究
昨天学习了java的反射机制,今天继续深入学习一下。
一、通过反射操作数组
反射不光只能用在类中,也可用在任意的引用数据类型上。当然包括数组。
通过java.lang.reflect.Array 类 可操作数组,java.lang.reflect.Array 类 下面提供了很多方法。
例如
public static Object get(Object array,int index)throws IllegalArgumentException,ArrayIndexOutOfBoundsException //得到数组中的值
下面演示如何操作
Integer [] temp = {1,2,3}; //声明一个数组 Class<?> c1 = temp.getClass().getComponentType(); //取得数组的class对象 System.out.println(c1.getName()); System.out.println("数组中第一个元素的值: "+Array.get(temp,0)); //得到数组中第一个元素 Array.set(temp, 0, 0); //改变数组中第一个元素 System.out.println("数组中第一个元素的值: "+Array.get(temp,0));
通过Array类操作temp这个数组。
输出结果如下
java.lang.Integer 数组中第一个元素的值: 1 数组中第一个元素的值: 0
二、动态代理
什么是代理设计
这里讲一下什么是代理模式。
代理模式的初衷就是,怎样才能在不直接操作对象的情况下,对对象进行访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 实际上在我的android项目 nju-wlan中对wifi的和gprs的控制就是用了代理模式。
请看代码
package com.iip; interface People{ //接口 public void say(String name,int age); } class Chinas implements People{ //真实的实现类 public Chinas(){ } @Override public void say(String name, int age) { // TODO Auto-generated method stub System.out.println(name + " " +age); } } class ChinaProxy implements People{ //代理类 People p = null; public ChinaProxy(People p) { // TODO Auto-generated constructor stub this.p = p; } @Override public void say(String name, int age) { // TODO Auto-generated method stub this.p.say(name, age); } } public class Proxy { public static void main(String[] args ){ People p = new ChinaProxy(new Chinas()); p.say("lamport", 2013); } }
看了这段代码,可能会想,那么这个代理有什么用呢?似乎看不到具体有什么好处啊!! 其实这样的主要好处是真正操作的类和接口实现的类并不存在联系,即减小了他们之间的耦合性。
这种代理实际上称之为静态代理,因为一个代理类只为一个接口服务。
如果有很多接口的话,每个接口都要有一个代理类。这样的话有很多重复。
在java中要想实现动态代理机制。需要java.lang.reflect.InvocationHandler 和 java.lang.reflect.Proxy 类的支持。
下面看 InvocationHandler接口,查看http://docs.oracle.com/javase/8/docs/api/ 文档下java.lang.reflect.InvocationHandler 这个接口中只要这一个抽象方法。
public interface InvocationHandler {
Object invoke(Object proxy,Method method,Object[] args) throws Throwable
}
参数说明:
proxy :被代理的对象
method:要调用的方法
args:方法调用时所需要的参数
可以将InvocationHandler的子类想象成一个代理的最终操作类。
Proxy类是专门完成代理的操作类,可通过此类为一个或者多个接口动态的生成实现类。此类提供如下的操作方法,
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
参数说明:
ClassLoader :类的加载器 //如果想得到加载器的对象,肯定是用Class类来完成
//写了一个Demo
public class ClassLoaderDemo { public static void main(String[]args){ Proxy p = new Proxy(); System.out.println("类加载器:"+ p.getClass().getClassLoader().getClass().getName()); } }
输出为加载器的名字。
输出:
类加载器:sun.misc.Launcher$AppClassLoader
Class<?>[] interfaces :得到全部的接口
InvocationHandler h: 得到InvocationHandler 接口的子类实例
直接上代码。
package com.iip; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; interface People{ public void say(String name,int age); } class Chinas implements People{ //真实的实现类 public Chinas(){ } @Override public void say(String name, int age) { // TODO Auto-generated method stub System.out.println(name + " " +age); } } class myInvocationgHandler implements InvocationHandler{ //使用动态代理 private Object obj; public Object bind(Object obj){ //绑定真实主题类 this.obj = obj; return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader() , obj.getClass().getInterfaces(), this); //取得代理对象 } @Override public Object invoke(Object proxy, Method method, Object[] args) //动态调用方法 throws Throwable { // TODO Auto-generated method stub Object object = method.invoke(this.obj, args); return object; } } public class Proxy { public static void main(String[] args ){ People p = (People) new myInvocationgHandler().bind(new Chinas()); //绑定到动态代理中 p.say("lamport", 2013); } }
动态代理的好处,就是省去很多重复的代码。在spring中底层实现,也使用了动态代理。
以上就是我今天的学习结果。最近想重新复习数据结构,由于很长时间没看过了,很多都忘了,有必要再复习下。树、图、搜索、遍历等等。