Java编程思想——第14章 类型信息(二)反射
六、反射:运行时的类信息
我们已经知道了,在编译时,编译器必须知道所有要通过RTTI来处理的类。而反射提供了一种机制——用来检查可用的方法,并返回方法名。区别就在于RTTI是处理已知类的,而反射用于处理未知类。Class类与java.lang.reflect类库一起对反射概念进行支持,该类库包含Field、Method以及Constructor(每个类都实现了Member接口)。这些类型是由JVM运行时创建的,用来表示未知类种对应的成员。使用Constructor(构造函数)创建新的对象,用get(),set()方法读取和修改与Field对象(字段)关联的字段,用invoke()方法调用与Method对象(方法)关联的方法。这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。
其实,当反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,在做其他事情之前必须先加载这个类的Class对象。因此,那个类的.class文件对于JVM来说必须时可获取的(在本地或网络上)所以反射与RTTI的区别只在于:对于RTTI来说,编译器在编译时打开和检查.class文件,而对于反射来说,.class文件在编译时是不可获得的,所以是运行时打开和检查.class文件。反射在需要创建更动态的代码时很有用。
七、动态代理
代理是基本的设计模式:为其他对象提供一种代理,以便控制对象,而在对象前或后加上自己想加的东西。
interface Interface { void doSomething(); void doSomeOtherThing(String args); } class RealObject implements Interface { @Override public void doSomething() { System.out.println("doSomething"); } @Override public void doSomeOtherThing(String args) { System.out.println("doSomeOtherThing" + args); } } class SimpleProxy implements Interface { private Interface proxyId; public SimpleProxy(Interface proxyId) { this.proxyId = proxyId; } @Override public void doSomething() { //将原有的doSomething 方法添加上了一个输出 这就是代理之后新增的东西 //就好比某公司代理游戏后加的内购 System.out.println("SimpleProxy doSomething"); proxyId.doSomething(); } @Override public void doSomeOtherThing(String args) { proxyId.doSomeOtherThing(args); //新增的东西可以在原有之前或之后都行 System.out.println("SimpleProxy doSomeOtherThing" + args); } } public class SimpleProxyDemo { static void consumer(Interface i) { i.doSomething(); i.doSomeOtherThing(" yi gi woli giao"); } public static void main(String[] args) { consumer(new RealObject()); System.out.println("----- ----- -----"); consumer(new SimpleProxy(new RealObject())); } }
结果:
doSomething doSomeOtherThing yi gi woli giao ----- ----- ----- SimpleProxy doSomething doSomething doSomeOtherThing yi gi woli giao SimpleProxy doSomeOtherThing yi gi woli giao
因为consumer()接受的Interface,所以无论是RealObject还是SimpleProxy,都可以作为参数,而SimpleProxy插了一脚 代理了RealObject加了不少自己的东西。
java的动态代理更前进一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;interface Interface { void doSomething(); void doSomeOtherThing(String args); }