Java类加载机制
Posted zhanhao777
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java类加载机制相关的知识,希望对你有一定的参考价值。
类加载器的种类
- 启动类加载器(Bootstrap ClassLoader)
System.out.println(System.getProperty("sun.boot.class.path"));
执行结果:D:javajdkjrelib esources.jar;D:javajdkjrelib t.jar;D:javajdkjrelib sunrsasign.jar;D:javajdkjrelibjsse.jar;D:javajdkjrelibjce.jar;D:javajdkjrelibcharsets.jar;D:javajdkjrelibjfr.jar;D:javajdkjreclasses
负责加载JRE的核心类库,如JRE目标下的rt.jar,charsets.jar等。
- 扩展类加载器(Extension ClassLoader)
System.out.println(System.getProperty("java.ext.dirs"));
执行结果:D:javajdkjrelibext;C:WindowsSunJavalibext
负责加载JRE扩展目录ext中jar类包
- 系统类加载器(Application ClassLoader)
System.out.println(System.getProperty("java.class.path"));
执行结果:D:javajdkjrelibcharsets.jar;D:java epostorycomalibabaastjson.2.49astjson-1.2.49.jar;D:java epostorymysqlmysql-connector-java.1.14mysql-connector-java-5.1.14.jar;D:SoftIntelliJ IDEAIntelliJ IDEA 2018.2.6libidea_rt.jar。由于执行结果太长我这里就贴了一部分。
负责加载ClassPath路径下的类包
- 用户自定义加载器(User ClassLoader)
负责加载用户自定义路径下的类包
类加载器面试问题
System.out.println(String.class.getClassLoader());
这是一道比较常见的题,本意是查看String用的什么类加载器,String属于rt.jar java.lang.string,但是执行结果为null。
rt.jar 是由Bootstrap ClassLoader来加载,但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后。总结一句话来说就是他是由C++编写的,所以查看String类加载器得到的结果为null。
类加载机制
全盘负责委托机制
当一个ClassLoader加载一个类的时候,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也由ClassLoader载入。
双亲委派机制
指先委托父类加载器寻找目标类,在找不到的情况下载自己的路径中查找并载入目标类。
双亲委派模式的优势
沙箱安全机制:比如自己写的String.class类不会被加载,这样可以防止核心库被随意篡改。
避免类的重复加载:当父ClassLoader已经加载了该类的时候,就不需要子CJlassLoader再加载一次。
几种方式加载class文件?
jar、网络传输二进制文件、本地系统加载二进制文件、数据库存放class文件、jit动态加载。
加载机制面试问题
用网络传输的方式和jar包加载的方式加载同一个class文件,那么在jvm中这两个类是否相同?
答案:虽然是同一份class字节码文件,但是由于被两个不同的ClassLoader实例所加载,所以JVM认为它们就是两个不同的类。
类的生命周期
加载阶段:磁盘中的class文件加载到内存中(方法区)。
连接阶段:
验证:1、class文件格式验证 魔术因子、主次版本号;
2、元数据验证 是否有父类、final不能进行重写;
3、字节码验证 指令、选择、循环;
4、符号验证 Person person = new Person();
准备:根据类型进行初始化赋值 int 0。
解析:符号引用 -> 直接引用 类装载器装入类所引用的其他类
四类解析:
类接口:是否数组类型(被动加载)-> 给一组空间, 否则直接初始化并给初始化空间
字段解析:本类字段 父类空间
类方法解析:当前类中找 -> 父类 -> NoSuchMethodError
接口方法的解析:实现类中的方法
准备过程中有一道经典的面试题:在准备阶段以下两个参数的值分别的多少?
public final static int age = 10;
public static int age = 10;
答案:用final修饰的属于常量在准备过程中就已经赋值所以等于10;没有用final修饰的则值为0。
生命周期中比较重要的概念
符号引用:javac 编译过程中不分配存储空间,new Person();用助记符来表示,实际上并不是真正的存储空间。
直接引用:在第二链接阶段的解析过程中由符号引用转换为直接引用,这个时候才真正分配存储空间。
主动使用:不使用的时候也加载。
被动使用:在使用的时候再加载,也就是所谓的延迟加载。
Java中的6种主动使用
这里我们简单准备了两个测试用的类,下面我们进行简单的测试
场景一:
场景二:
场景三:
场景四:
场景五:
场景六:其实细心的小伙伴可能已经发现了,main方法作为一个入口肯定会引起主动加载的。
例举两种被动使用的情况
场景一:
场景二:
这里先把Person中的age变量前面加上final
public final static int age = 10;
总结
Jvm这部分东西实际工作中用到的其实微乎其微,更多的是用来应对面试,当然也并不是说了解这些东西没有必要,如果能真正理解的话对你实际工作也还是有一定的帮助的,就比如上面提到的面试题你先看看自己是否都能答上来。
以上是关于Java类加载机制的主要内容,如果未能解决你的问题,请参考以下文章