Java编程思想——第14章 类型信息(二)反射

6、反射:运行时的类信息

  咱们已经知道了,在编译时,编译器必须知道全部要经过RTTI来处理的类。而反射提供了一种机制——用来检查可用的方法,并返回方法名。区别就在于RTTI是处理已知类的,而反射用于处理未知类。Class类与java.lang.reflect类库一块儿对反射概念进行支持,该类库包含Field、Method以及Constructor(每一个类都实现了Member接口)。这些类型是由JVM运行时建立的,用来表示未知类种对应的成员。使用Constructor(构造函数)建立新的对象,用get(),set()方法读取和修改与Field对象(字段)关联的字段,用invoke()方法调用与Method对象(方法)关联的方法。这样,匿名对象的类信息就能在运行时被彻底肯定下来,而在编译时不须要知道任何事情。java

  其实,当反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,在作其余事情以前必须先加载这个类的Class对象。所以,那个类的.class文件对于JVM来讲必须时可获取的(在本地或网络上)因此反射与RTTI的区别只在于:对于RTTI来讲,编译器在编译时打开和检查.class文件,而对于反射来讲,.class文件在编译时是不可得到的,因此是运行时打开和检查.class文件。反射在须要建立更动态的代码时颇有用。程序员

7、动态代理

  代理是基本的设计模式:为其余对象提供一种代理,以便控制对象,而在对象前或后加上本身想加的东西。设计模式

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加了很多本身的东西。ide

  java的动态代理更前进一步,由于它能够动态建立代理并动态地处理对所代理方法的调用。在动态代理上所作的全部调用都会被重定向到单一的调用处理器上,它的工做是揭示调用的类型并肯定相应的对策。函数

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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 DynamicProxyHandler implements InvocationHandler {
    private Object proxyId;

    public DynamicProxyHandler(Object proxyId) {
        this.proxyId = proxyId;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
        if (args != null) {
            for (Object arg : args) {
                System.out.println(" " + arg);
            }
        }
        return method.invoke(proxyId, args);
    }
}

public class SimpleProxyDemo {
    static void consumer(Interface i) {
        i.doSomething();
        i.doSomeOtherThing(" yi gi woli giao");
    }

    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        consumer(realObject);
        System.out.println("-----  -----  -----");
     //动态代理 能够代理任何东西 Interface proxy
= (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject)); consumer(proxy); } }

结果:this

doSomething
doSomeOtherThing yi gi woli giao
-----  -----  -----
**** proxy:class $Proxy0, methodpublic abstract void Interface.doSomething(), args:null
doSomething
**** proxy:class $Proxy0, methodpublic abstract void Interface.doSomeOtherThing(java.lang.String), 
args:[Ljava.lang.Object;@7ea987ac  yi gi woli giao
doSomeOtherThing yi gi woli giao

经过Proxy.newProxyInstance()能够建立动态代理,这个方法须要三个参数:spa

1. 类加载器:能够从已经被加载的对象中获取其类加载器;设计

2. 你但愿该代理实现的接口列表(不能够是类或抽象类,只能是接口);代理

3. InvocationHandler接口的一个实现;

在 invoke 实现中还能够根据方法名处对不一样的方法进行处理,好比:

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args);
        if (args != null) {
            for (Object arg : args) {
                System.out.println(" " + arg);
            }
        }
        if (method.getName().equals("doSomething")) { System.out.println("this is the proxy for doSomething"); } return method.invoke(proxyId, args);
    }

还能够对参数或方法进行更多的操做由于 你已经获得了他们 尽情的使用你的代理权吧 ~~ 先加它十个内购。

9、接口与类型信息

  interface关键字的一种重要目标就是容许程序员隔离构件,进而下降耦合。反射,能够调用全部方法,甚至是private。惟独final是没法被修改的,运行时系统会在不抛任何异常的状况接受任何修改尝试,可是实际上不会发生任何修改。

    void callMethod(Object a, String methodName) throws Exception {
        Method method = a.getClass().getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(a);
    }
相关文章
相关标签/搜索