类的完整生命周期
Java源文件(.java文件) -->编译
Java字节码(.class文件, 存储于本地本地硬盘、网络、内存等) -->类加载
加载 <主要的考点>
验证
准备
解析
Class对象 -->实例化
实例对象
使用
卸载
什么时候触发类加载?
1. 使用new关键字实例化对象,读取或者设置一个类的静态变量的时候,调用类的静态方法的时候;
2. 对类进行反射调用的时候;
3. 初始化子类时,父类会先被初始化;
4. 对类使用动态代理的时候需要先被初始化;
JDK自带类加载器
参考http://blog.csdn.net/briblue/article/details/54973413
启动类加载器 Bootstrap ClassLoader
加载的范围:存放在 \lib 目录中的,加载到虚拟机内存中
扩展类加载器 Extension ClassLoader
加载的范围:存放在\lib\ext目录中的所有类库,开发者可以直接使用;
应用程序加载器 Application ClassLoader
加载用户类路径上指定的类库,开发者可以直接使用,一般情况下这个就是程序中默认的类加载器;
类加载器加载顺序
1. Bootstrap CLassloder
2. Extention ClassLoader
3. AppClassLoader
4. 用户自定义类加载器
谈下你对双亲委派模型理解?
双亲委派模型过程
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
双亲委派模型好处
Java类随着它的类加载器一起具备了带有优先级的层次关系,保证java程序稳定运行
具体步骤:
1. 一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器。
2. 递归,重复第1部的操作。
3. 如果ExtClassLoader也没有加载过,则由Bootstrap ClassLoader出面,它首先查找缓存,如果没有找到的话,就去找自己的规定的路径下,也就是sun.mic.boot.class下面的路径。找到就返回,没有找到,让子加载器自己去找。
4. Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回,查找不成功,再向下让子加载器找。
5. ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回。如果没有找到就让子类找,如果没有子类会怎么样?抛出各种异常。
JDK的双亲委派逻辑体现在 java.lang.ClassLoader.loadClass(String name, boolean resolve)中
自定义的ClassLoader通常通过重写findClass()方法实现自己的类加载逻辑
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException{
synchronized (getClassLoadingLock(name)) {
Class c = findLoadedClass(name); // First, check if the class has already been loaded
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false); //load the class parent
} else {
c = findBootstrapClassOrNull(name); //if parent is null, load the class by Bootstrap ClassLoader, which will invoke native method
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
c = findClass(name); //if c is still null, using customer classLoader
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
可以绕过双亲委托逻辑吗
可以,继承java.lang.ClassLoader.loadClass,直接调用defineClass()方法就可以了
http://blog.csdn.net/qq_26182553/article/details/79641451
为什么要区分不同类加载器,有什么好处
不同类加载器的主要区别在于加载路径不同, 这样保证了java.lang.String的字节码一定是先从<JAVA_HOME>\lib路径下查找,只有再父加载器加载不到的情况下才会委托给当前加载器去加载,
这样保证了系统的类一定是正确的被加载,防止对系统类的篡改,或者由于同名造成加载对象的混乱。
同一个tomcat容器下的两个应用以及lib目录中都有UserServiceImpl类,tomcat怎么样保证类的隔离性?
类加载器与类的唯一性:
类加载器虽然只用于实现类的加载动作,但是对于任意一个类,都需要由加载它的类加载器和这个类本身共同确立其在Java虚拟机中的唯一性。通俗的说,JVM中两个类是否“相等”,首先就必须是同一个类加载器加载的,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要类加载器不同,那么这两个类必定是不相等的。
Tomcat目录结构中,有三组目录(“/common/*”,“/server/*”和“shared/*”)可以存放公用Java类库,此外还有第四组Web应用程序自身的目录“/WEB-INF/*”,把java类库放置在这些目录中的含义分别是:
放置在common目录中:类库可被Tomcat和所有的Web应用程序共同使用。
放置在server目录中:类库可被Tomcat使用,但对所有的Web应用程序都不可见。
放置在shared目录中:类库可被所有的Web应用程序共同使用,但对Tomcat自己不可见。
放置在/WebApp/WEB-INF目录中:类库仅仅可以被此Web应用程序使用,对Tomcat和其他Web应用程序都不可见。
注意:tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。