Java反射(6)反射的经典应用----JDK动态代理
目录:
1.类和接口的区别
2.静态获取接口的实例----接口的实现类
3.动态获取接口的实例----动态代理
1.类和接口的区别
Java中class
和interface
的区别:
- 可以实例化
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