Java反射(6)反射的经典应用----JDK动态代理

目录:

1.类和接口的区别
2.静态获取接口的实例----接口的实现类
3.动态获取接口的实例----动态代理

1.类和接口的区别

Java中classinterface的区别:

  • 可以实例化class(非abstract类);
  • 不能实例化interface

所有interface类型的变量总是通过向上转型并指向某个实例的:

CharSequence cs = new StringBuilder();

2.静态获取接口的实例----接口的实现类
传统编码方式流程如下:
首先定义接口:

public interface Hello {
    void morning(String name);
}

然后编写实现类:

public class HelloImpl implements Hello {
    public void morning(String name) {
        System.out.println("Good morning, " + name);
    }
}

最后创建实例,转型为接口并调用:

Hello hello = new HelloImpl();
hello.morning("Bob");

3.动态获取接口的实例----动态代理
目的:(不编写实现类的前提下)为了获得接口的实例,并实现接口中的方法,并调用该方法。

public class Main {
    public static void main(String[] args) {
//1.创建一个handler。它负责接口中的方法实现
        InvocationHandler handler = new InvocationHandler() {
            @Override
/invoke函数:代理对象;想调用的方法;方法的参数
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
//2.创建一个Proxy的instance。需要传入三个参数:接口的类加载器;要实现的接口;调用方法的handler
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler

        hello.morning("Bob");
    }
}

interface Hello {
    void morning(String name);
}

在运行期动态创建一个interface实例的方法如下:

  • 定义一个InvocationHandler实例,它负责实现接口的方法调用;
  • 通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
    ** 使用的ClassLoader,通常就是接口类的ClassLoader
    ** 需要实现的接口数组,至少需要传入一个接口进去;
    ** 用来处理接口方法调用的InvocationHandler实例。
  • 将返回的Object强制转型为接口。

动态代理实际上是JDK在运行期动态创建class字节码并加载的过程.
把上面的动态代理改写为静态的实现类大概长这样:

public class HelloStaticImpl implements Hello {
    InvocationHandler handler;
    public HelloDynamicProxy(InvocationHandler handler) {
        this.handler = handler;
    }
    public void morning(String name) {
        handler.invoke(//由handler去调用函数
           this,//Proxy对象
           Hello.class.getMethod("morning"),//方法名
           new Object[] { name });//方法参数
    }
}

参考
https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984

posted @ 2020-04-17 13:49  JohnTesla  阅读(255)  评论(0编辑  收藏  举报