面试必看--Java类的加载过程

Posted LuckyWangxs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试必看--Java类的加载过程相关的知识,希望对你有一定的参考价值。

1. 什么是类的加载过程

        一个Java文件从编码完成到最终运行,一般会经历两个阶段:编译期、运行期。编译,即通过javac命令,将Java文件转化为二进制字节码文件,即.class文件;运行,则是将.class文件交给JVM执行。而本文所说的类加载过程就是将.class文件中类的元信息加载进内存,创建Class对象并进行解析、初始化类变量等的过程
        JVM并不是一开始就会将所有的类加载到内存,而是用到某个类,才会去加载,只加载一次,后续会说到类的加载时机

2. 类加载详解

        类加载分为三个部分:加载、连接、初始化

2.1 加载

        类的加载主要的职责为将.class文件读入内存(JDK1.7及之前为JVM内存,JDK1.8及之后为本地内存),并在堆内存中为之创建Class对象,作为.class进入内存后的数据的访问入口。
        ++拓展: 在JDK1.7及以前,Hot Spot JVM(普遍在用的JVM)存在一块叫做方法区的内存,也称之为永久代,这块区域用于存放类的元数据信息,包括类的字段,版本,方法等,这块区域,可以理解为.class文件进入内存后的位置。在JDK1.8,取消了方法区,取而代之的是元数据区,该元数据区并非JVM内存,而是本地内存。此外在JDK1.7时,将常量池从方法区移除,在堆内存开辟了一块空间作为常量池,有人说这是为取消方法区做的准备。更多请点我看思维导图总结
        ++加分项: 为何取消方法区?
        官方说法为:移除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代
        现实使用中存在问题:方法区存储类的元数据信息,我们不清楚一个程序到底有多少类需要被加载,且方法区位于JVM内存,我们不清楚需要给方法区分配多大内存,太小容易PermGen OOM,太大,在触发Full GC时又极其影响性能,同时还存在一些内存泄露的问题

2.2 连接

        类的连接分为三个阶段:验证、准备、解析。
         验证: 该阶段主要是为了保证加载进来的字节流符合JVM的规范,不会对JVM有安全性问题。其中有对元数据的验证,例如检查类是否继承了被final修饰的类;还有对符号引用的验证,例如校验符号引用是否可以通过全限定名找到,或者是检查符号引用的权限(private、public)是否符合语法规定等。
        准备: 准备阶段的主要任务是为类的类变量开辟空间并赋默认值。
1、静态变量是基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0
2、静态变量是引用类型的,默认值为null
3、静态常量默认值为声明时设定的值
例如:public static final int i = 3; 在准备阶段,i的值即为3
        解析: 该阶段的主要职责为将Class在常量池中的符号引用转变为直接引用。
        符号引用即字符串,说白了可以是一个字段名,或者一个方法名;直接引用即偏移量,说白了就是类的元信息位于内存的地址串,例如,一个类的方法为test(),则符号引用即为test,这个方法存在于内存中的地址假设为0x123456,则这个地址则为直接引用。

2.3 初始化

        该阶段主要是为类的类变量初始化值的,初始化有两种方式:
1、在声明类变量时,直接给变量赋值
2、在静态初始化块为类变量赋值

3. 类的加载时机(包括加载、连接、初始化)

  1. 创建该类的实例
  2. 调用该类的类方法
  3. 访问类或接口的类变量,或为类变量赋值
  4. 利用反射Class.forName(String name, boolean initialize,ClassLoader loader);
    当使用ClassLoader类的loadClass()方法来加载类时,该类只进行加载阶段,而不会经历初始化阶段,使用Class类的静态方法forName(),根据initialize来决定会不会初始化该类,不传该参数默认强制初始化
  5. 初始化该类的子类
  6. 运行main方法,main方法所在类会被加载

类加载顺序

  1. 先加载并连接当前类
  2. 父类没有被加载,则去加载、连接、初始化父类,依旧是先加载并连接,然后再判断有无父类,如此循环,所以JVM先将Object加载
  3. 如果类中有初始化语句,包括声明时赋值与静态初始化块,则按顺序进行初始化

由此可以理解类的初始化顺序:先执行父类静态变量赋值、父类静态初始化块,再执行子类静态属性赋值、静态初始化块。

4. 总结

        在Java类加载这块,还有很多内容需要学习,例如类加载器有几种,加载机制有几种,类加载器加载.class的步骤等,这些内容都掌握了,我们才能在面试中脱颖而出。想要高薪,我们不仅要知其然,更要知其所以然
        我的思维导图(思维导图地址)还总结了有关GC垃圾回收的,以及类加载器相关的内容,感兴趣的可以看看
        这篇文章就到这里了,如有问题,欢迎各位大佬指正,切不可误人子弟。

以上是关于面试必看--Java类的加载过程的主要内容,如果未能解决你的问题,请参考以下文章

面试必看:java面试考点干货精讲视频教程

跳槽者应届生必看JAVA面试题系列 - 基础类知识篇

必看!100道Java程序员面试题(含答案)!

面试必看--Java—GC垃圾回收

MySQL面试题(无答案版) 中高级必看

最新 Java 面试职场指南,小白必看!