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 epostorycomalibaba astjson.2.49 astjson-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种主动使用

这里我们简单准备了两个测试用的类,下面我们进行简单的测试

技术图片

Person类

技术图片

 

场景一:

技术图片

new 的过程中引起了类的主动加载

场景二:

技术图片

访问类的静态变量

场景三:

技术图片

访问类的静态方法

场景四:

技术图片

反射调用

场景五:

技术图片

初始化子类引起父类的主动使用

场景六:其实细心的小伙伴可能已经发现了,main方法作为一个入口肯定会引起主动加载的。

例举两种被动使用的情况

场景一:

技术图片

对象数组初始化

场景二:

这里先把Person中的age变量前面加上final

public final static int age = 10;
技术图片

调用静态常量

总结

Jvm这部分东西实际工作中用到的其实微乎其微,更多的是用来应对面试,当然也并不是说了解这些东西没有必要,如果能真正理解的话对你实际工作也还是有一定的帮助的,就比如上面提到的面试题你先看看自己是否都能答上来。

以上是关于Java类加载机制的主要内容,如果未能解决你的问题,请参考以下文章

[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的

JAVA类加载机制详解

Java类加载机制

JAVA 类加载机制

详解JAVA类加载机制

Java虚拟机类加载机制