Java ClassLoader & 反射
ClassLoader
JDK默认提供了如下几种ClassLoader:
- Bootstrap ClassLoader 用C++语言写的,它是在Java虚拟机启动后初始化的,负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath路径及%JAVA_HOME%/jre/classes中的类。
- Extension ClassLoader 用Java写的,Bootstrap loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrap loader。ExtClassLoader负责加载%JAVA_HOME%/jre/lib/ext下类。
- Application ClassLoader Bootstrap loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为ExtClassLoader。AppClassLoader也是用Java写成的。ClassLoader中有个getSystemClassLoader方法,返回的正是AppClassLoader,负责加载classpath所指定的位置的类和jar文档,它也是Java程序默认的类加载器。
它们之间的关系如下图描述:
双亲委托模型
Java中ClassLoader的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用了如下几个步骤:
1、当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。
2、当前ClassLoader的缓存中没有找到要加载的类时,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到Bootstrap ClassLoader。
3、当所有的父类加载器都没有加载到的时候,再由当前的类加载器加载,并放入它自己的缓存中。
说到这里大家可能会想,Java为什么要采用这样的委托机制?理解这个问题,我们引入另外一个关于Classloader的概念“命名空间”, 它是指要确定某一个类,需要类的全限定名以及加载此类的ClassLoader来共同确定。也就是说即使两个类的全限定名是相同的,但是因为不同的 ClassLoader加载了此类,那么在JVM中它是不同的类。明白了命名空间以后,我们再来看看委托模型。采用了委托模型以后加大了不同的 ClassLoader的交互能力,比如上面说的,我们JDK本生提供的类库,比如hashmap,linkedlist等等,这些类由bootstrp 类加载器加载了以后,无论你程序中有多少个类加载器,那么这些类其实都是可以共享的,这样就避免了不同的类加载器加载了同样名字的不同类以后造成混乱。
自定义ClassLoader
Java容许应用程序自定义ClassLoader,要自定义ClassLoader需要通过继承java.lang.ClassLoader来实现,以下就是其中的关键函数loadClass():
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
//检查class是否已经被加载过了
Class c = findLoadedClass(name);
if (c == null) {
...
try {
if (parent != null) {
//如果没有被加载,且指定了父类加载器,则委托父加载器加载
c = parent.loadClass(name, false);
} else {
//如果没有父类加载器,则委托bootstrap加载器加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
...
//如果父类加载没有加载到,则通过自己的findClass来加载
//我们在写自己的ClassLoader的时候,如果想遵循双亲委托机制,则只需要override findClass
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
反射
Reflection机制允许程序在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,并可以在执行过程中,动态生成instances,变更fileds内容或唤起methods。
反射机制获取类:
- Class c1 = Class.forName(“Employee”);
- Class c2 = Employee.class;
- Employee e = new Employee();
Class c3 = e.getClass();
获取类以后再创建它的对象:
- Object o = c.newInstance();
获取类的构造方法:
- getConstructors()
- getConstructor(Class[] params)
- getDeclaredConstructors()
- getDeclaredConstructor(Class[] params)
获取类的成员方法:
- getMethods()
- getMethod(String name, Class[] params)
- getDeclaredMethods()
- getDeclaredMethod(String name, Class[] params)
获取类的成员变量:
- getFields()
- getField(String name)
- getDeclaredFields()
- getDeclaredField(String name)
参考链接:
1. http://my.oschina.net/aminqiao/blog/262601
2. http://www.cnblogs.com/ITtangtang/p/3978102.html
3. http://blog.csdn.net/liujiahan629629/article/details/18013523