相信许多学Java的小伙伴为了把自己简历包装的更好看一些,往往会去学习一下Java的高级篇,把JVM的一些知识学一下再写到简历里面,就会让面试官觉得你不只是学了一下Java的if-else和一些简单的API。而当我们遇到类加载机制这个问题的时候,由于这个过程我们是看不见的,也就没有办法去应用然后熟能生巧地理解,大多数时候都是靠背。这篇文章我们就好好盘一下这个类加载机制!让你和面试官有谈资!
先放一张大家耳熟能详的图
这张图相信大家都不陌生,很多博客和书上都是这么说的,类加载机制是先加载然后连接,连接又分为三个步骤分别是验证,准备,解析。连接完之后下一步是初始化。给人的直观感受会是这整个过程是紧密相连一步接着一步走的,但其实不然!切听我细细分说。
首先,我们谈谈Java的编译,我们都知道Java是一门半编译半解释型的语言。我们写好的一个.java文件经过Javac的编译形成字节码.class文件,.class文件又由JVM加载,运行的时候解释器将字节码解释成一行行机器码来执行。其中的字节码文件被JVM加载到运行时内存的这个过程就叫做类加载。
我们在文件的角度去分析了类加载是怎么样的一个过程,那么具体到虚拟机里面又是怎么一回事呢?
第一步是加载,用一句话概括,加载是一个读取Class文件,将其转化为某种静态数据结构存储在方法区内,并在堆中生成一个便于用户调用的java.lang.Class类型的对象的过程。这一步可以深挖几个谈资。
第二步是验证阶段,验证顾名思义,就是对这个对象进行检验,检验的内容大概分为以下几点。
谈资在于:其实这三个验证过程并不是紧密相连的,它们是分散开的,第一个对文件格式的检验其实发生在加载阶段前面,而第三个符号引用的验证其实发生在后面的解析阶段结束。换句话说,这个图画的不是很标准。
第三步准备阶段,这阶段十分简单,一句话,把对象的静态成员变量赋0值。
第四步解析阶段,解析阶段做的事情是,把符号引用替换为直接引用。
简单的一句话怎么能让面试官耳目一新呢?这里必须要有点谈资,谈资就是这里面的符号引用和直接引用的理解:比如一个类A,它引用了B这个类,在编译阶段,A这个类是不知道B有没有被加载的,也不知道B的实际地址,这个时候在A的class文件中将会用一个字符串来代表B的地址。这个字符串就被称为符号引用。在运行的时候,如果触发了A的类加载,到解析阶段发现B没有加载,这个时候,会触发B的类加载,此时A中的字符串会被B的地址所代替,这就叫直接引用。
解析又分为静态解析和动态解析,因为Java有多态机制,如果上面提到的B是一个实体类,那么这样的解析称为静态解析,如果B是一个接口或者是抽象类的时候,这个时候就没有办法确定这个引用的实际地址,既然没有那就先留着。等到运行阶段发生了调用,这个时候虚拟机中的调用栈将会得到具体的类型信息,这个时候再进行解析就可以得到明确的直接引用。这个过程就叫做动态绑定。这也是为什么解析阶段会发生在初始化阶段之后,实现后期绑定。
第五步是初始化阶段初始化阶段就很简单了,先判断代码中是否存在主动资源初始化操作,如果有的话,那么执行。主动资源初始化动作是指class层面的一些静态代码块,成员变量的赋值操作。 肯定是不包括构造函数的,构造函数是对象层面的,这个class是类层面的。
好了,整个类加载过程就是这样了。面试官问你怎么谈?咱就这么谈!