多角度查看类的装载

多角度查看类的装载

写在前面:本篇文章主要搬自本人的云笔记,借鉴了一些文章,记不得出处了,有不当之处,欢迎指正,共同学习;

一、类装载的过程

类装载是通过类加载器将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;

总结

整理不宜,转载请指明出处,共同进步吧!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值