6、java动态代理:两个重要类:
1、Proxy:jdk提供的帮助类(类似于工厂)用于生成代理实例,Proxy.newProxyInstance(classLoader, interfaces, invocationHandler)。2、InvocationHandler(调用处理器):代理实例的所有方法调用都由处理器InvocationHandler.invoke方法处理(传入的代理接口的方法)。重要约束:java动态代理是基于接口的,代理实例只实现被代理接口的方法,真实实现类中的其他方法不作处理。
1、RealObject implements Hello,可以实现多个接口。
2、XXHandler implements InvocationHandler,调用处理器invoke方法的通用实现,通过反射调用目标类(真实实现类)的真实实现public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("before invoke, method=" + method.getName()); result = method.invoke(target,args); System.out.println("after invoke, result=" + result); return result;}
3、通过Proxy,新建一个代理实例:RealObject real = new RealObject();Class?[] interfaces = new Class[] { Hello.class, ..};//指定需要代理的接口,代理全部接口则real.getClass().getInterfaces();InvocationHandler handler = new XXHandler();Hello proxy = (Hello) Proxy.newProxyInstance(real.getClass().getClassLoader(), interfaces, handler);proxy.hello("hi");
动态生成的proxy,名称类似$Proxy0,说明是Proxy的子类。Proxy有个重要参数:protected InvocationHandler h; 代理类的调用处理器class=class com..$Proxy0superClass=class java.lang.reflect.Proxyinterfaces=[interface com..Hello,..]invocationHandler=com..XXInvocationHandler@a09ee92
调用大致流程:proxy.hello -> h.invoke -> method.invoke(target, args) 然后再通过反射,调用目标方法// JDK代理类具体实现类似public final class $Proxy0 extends Proxy implements Hello{ ... public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } ... @Override public final String sayHello(String str){ ... return super.h.invoke(this, m3, new Object[] {str});// 将方法调用转发给invocationhandler ... } ...}
7、类加载机制与反射机制双亲委托机制:类的加载过程采用委托模式实现,类加载器在加载类之前会先递归的去尝试使用父加载器加载;虚拟机有一个内建的启动类加载器(bootstrap ClassLoader),该加载器没有父加载器,可以作为其他加载器的父加载器。Bootstrap|ExtClassLoader|AppClassLoader|User ClassLoader自定义类加载器
1、Bootstrap ClassLoader启动类加载器,C++实现,加载/lib 目录中的文件,并且该类加载器只加载特定名称的文件(如 rt.jar),而不是该目录下所有的文件。
2、ExtClassLoader,负责加载\lib\ext目录中或系统变量java.ext.dirs 所指定的目录中的文件。
3、AppClassLoader,负责加载用户类路径中的文件java.class.path。
系统类加载器:
系统类加载器默认就是AppClassLoader,main方法的加载器就是系统类加载器。
并且传给当前线程上下文的加载器也是AppClassLoader。即Thread getContextClassLoader(),默认也是AppClassLoader
自定义类加载器:
jdk ClassLoader已经干了大部分的活,ClassLoader实现了委派机制,很简单,继承ClassLoader,并且:
自定义类加载器只需要实现findClass,并在findClass方法中完成:
1,需要加载class文件(二进制流)
2,调用ClassLoader.defineClass传入二进制流
如下:
NetworkClassLoader loader = new NetworkClassLoader();
loader.loadClass("com....");
class NetworkClassLoader extends ClassLoader {
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
}
}
反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射API:
Class/Method/Field
Class cls = Class.forName("com.lvr.reflection.Person");
Field[] fields = cls.getFields();
getFields()获得某个类的所有的公共(public)的字段,包括父类
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段