多角度查看类的装载
写在前面:本篇文章主要搬自本人的云笔记,借鉴了一些文章,记不得出处了,有不当之处,欢迎指正,共同学习;
一、类装载的过程
类装载是通过类加载器将class文件内容加载到jvm内存区,该过程主要分为三个部分
加载
1. 通过classLoader加载class文件,并将.class文件读到内存中
2. 这里会创建一个class对象,且有且仅会创建一个class对象;
链接
1. 校验:检查有效性,校验一些符号引用什么的
2. 准备:分配内存(保存类信息使用),初始值(这里的初始值,是指的默认值,不是代码的赋值,在初始化阶段才会赋值)
1. 8种基本类型的初值,默认为0;
2. 引用类型的初值则为null;
3. 常量的初值即为代码中设置的值,final static tmp = abc, 那么该阶段tmp的初值就是abc
3. 解析: 将类的二进制数据中的符号引用替换为直接引用(这叫静态链接),部分符号引用在运行期间转化为直接引用,这种转化为动态链接
1. 符号引用:存储在常量池中的
1. 类和方法的全限定名
2. 字段的名称和描述符
3. 方法的名称和描述符。
2. 直接引用:内存地址
初始化:
执行类变量赋值,和静态代码块;
这里多说一下:关于常量池的知识
二、类加载器
双亲委托
一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象
代码看一下classLoad的关系
public class ClassLoadTest {
public static void main(String[] args) {
System.out.println("---------ClassLoadTest----------------------------");
ClassLoadTest test = new ClassLoadTest();
ClassLoader c1 = test.getClass().getClassLoader();
System.out.println(c1);
ClassLoader c2 = c1.getParent();
System.out.println(c2);
ClassLoader c3 = c2.getParent();
System.out.println(c3);
System.out.println("---------ArrayList----------------------------");
List<String> list = new ArrayList<>();
ClassLoader cl1 = list.getClass().getClassLoader();
System.out.println(cl1);
}
}
输出如下:
---------ClassLoadTest----------------------------
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@61bbe9ba
null
---------ArrayList----------------------------
null
可以看出ClassLoadTest是由AppClassLoader加载器加载的,AppClassLoader的Parent 加载器是 ExtClassLoader,但是ExtClassLoader的Parent为 null 是怎么回事呵,朋友们留意的话,Bootstrap Loader是用C++语言写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体,所以在java程序代码里试图打印出其内容时,我们就会看到输出为null。
代码看一下各classLoad要加载的jar
System.out.println("------------各classload加载的jar包--------------");
String bootstr = System.getProperty("sun.boot.class.path");
String[] bootstrs = bootstr.split(":");
//遍历BootStrapClassLoader加载的jar包
System.out.println("遍历BootStrapClassLoader加载的jar包路径************************");
for(int i=0;i<bootstrs.length;i++){
System.out.println(bootstrs[i]);
}
System.out.println("遍历ExtClassLoader加载的jar包路径************************");
String extstr = System.getProperty("java.ext.dirs");
String[] extstrs = extstr.split(":");
for(int i=0;i<extstrs.length;i++){
System.out.println(extstrs[i]);
}
System.out.println("遍历AppClassLoader加载的jar包路径************************");
String appstr = System.getProperty("java.class.path");
String[] appstrs = appstr.split(":");
for(int i=0;i<appstrs.length;i++){
System.out.println(appstrs[i]);
}
输出如下:
------------各classload加载的jar包--------------
遍历BootStrapClassLoader加载的jar包路径************************
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/sunrsasign.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jsse.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jce.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/charsets.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfr.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/classes
遍历ExtClassLoader加载的jar包路径************************
/Users/tiger/Library/Java/Extensions
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java
遍历AppClassLoader加载的jar包路径************************
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/charsets.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/deploy.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/dnsns.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jaccess.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/jfxrt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/localedata.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/nashorn.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunec.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext/zipfs.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/javaws.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jce.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfr.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfxswt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jsse.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/management-agent.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/plugin.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/ant-javafx.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/dt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/javafx-mx.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/jconsole.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/packager.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/sa-jdi.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/tools.jar
/Users/tiger/Documents/workSpace/github/algorithem/target/classes
/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
使用双亲委任原则的好处
1. 可以避免重复加载,父加载器加载完成后,子加载器就不会再加载了
2. 更加安全,很好的解决了各个类加载器的基础类的统一问题;如果不这样,各个自定义类都可加载自己定义的核心api;
总结
整理不宜,转载请指明出处,共同进步吧!