类加载器
类加载器和类加载器的作用:
java虚拟机中可以安装多个类加载器,系统默认三个主要BootStrap
类加载器也是java'类,因为其他事java类的来加载器本身也要蓓蕾加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap.(用C++语言写的一段二进制代码,不是一个java类)
java虚拟机中的所有类装载器采用具有父子关系的属性结构进行组织,在实例化每个类装载器对象时,需要为其制定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载
例:
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while (loader != null) {
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);
}
}
// 先后输出为:
// sun.misc.Launcher$AppClassLoader
// sun.misc.Launcher$ExtClassLoader
// null : 注null就代表是BootStrap类加载器,该加载器是顶级加载器,没有父类加载器
类加载器之间的父子关系和管辖范围:
BootStrap -> ExtClassLoader -> AppClassLoader(即通常所说的System ClassLoader)
它们的管辖范围依次是:JRE/lib/rt.jar -> JRE/lib/ext/*.jar -> CLASSPATH指定的所有jar或目录。
java类加载器委托机制
当Java虚拟机要加载一个类时,到底该派哪个类加载器去加载呢?
1.首先是当前线程的类加载器去加载线程中的第一个类。
2.如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。
3.还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
4.每个类加载器加载类时,又先委托给其上级类加载器
5.当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChlid方法,即使有,那么有多个儿子,找哪一个呢/
编写自己的类加载器知识相关:
1.自定义的类加载器必须继承ClassLoader
2.loadClass方法与findClass方法
3.defineClass方法
注:自定义的类加载器通常用于解密自己写的已加密的class字节码,否则即使别人拥有该class文件也无法被系统的类加载器正常加载。
动态代理
生活中的代理:生活中我们经常去商店买东西,而商店里的每件东西都是从代理那进货的。经常听说的全国总代理,XX区总代理,这就是生活中的代理。
程序中的代理:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,异常处理、日志、计算方法的运行时间、事务管理就需要我们编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
例:做一个程序中的代理
import java.lang.reflect.*;
import java.util.*;
public class ProxyTest {
public static void main(String[] args) throws Exception {
final ArrayList target = new ArrayList();
Collection proxy = (Collection) getProxy(target);
proxy.add("zxx");
proxy.add("lhm");
proxy.add("bxd");
System.out.println(proxy.size());
System.out.println(proxy.getClass().getName());
}
private static Object getProxy(final Object target) {
Object proxy = Proxy.newProxyInstance(target.getClass()
.getClassLoader(),// 获取类加载器
/ * new Class[]{Collection.class}, * /
target.getClass().getInterfaces(),// 获取接口
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()
+ " running time of " + (endTime - beginTime));
return retVal;
}
});
return proxy;
}
}