加载是类加载的第一阶段,在这一步中JVM规范要求完成了以下三件事:
-
通过一个类的全限定名来获取定义这个类的二进制字节流。
-
将这个字节流多代表的静态存储结构转化为方法区的运行时数据结构。
-
在内存中生成一个代表这个类的java.lang.Class对象。
以上要求其实并不具体,JVM的具体实现和应用都是比较灵活的。比如:获取这个类的二进制字节流,并没有说从哪获取,怎么获取,于是就有了从压缩包中读取(jar、war、ear)、从网络中获取(Applet)、运行时计算生成(动态代理)。对于不是数组的类的加载,我们可以定义自己的类加载器去控制字节流的获取方式。但是,对于数组类就不一样了,因为数组类本身不是通过类加载器创建的,而是JVM直接创建的。
验证
这一阶段是为了保证Class文件的字节流中包含的信息符合当前JVM的要求,并且不危害JVM自身的安全。大致分为以下四个阶段:
文件格式验证
验证字节流是否符合Class文件格式的规范,能不能被当前JVM处理。验证点比较多,比如:是否以魔数0xCAFEBABE开头、主次版本号是否在当前JVM的处理范围内、常量池的常量是否有不被支持的常量类型、CONSTANT_Utf8_info类型的常量中是否有不符合UTF8编码的数据等等。这个阶段是基于二进制字节流进行验证的,只有这个阶段验证通过了,字节流才能进入内存的方法区储存。
元数据验证
这个阶段主要是对类的元数据信息进行语义分析和校验,保证不存在不符合Java语言规范的元数据信息。比如:除了java.lang.Object以外的类是否有父类、是否继承了一个不允许被继承的类、非抽象类是否实现了其父类或接口中要求实现的所有方法、是否覆盖了父类的final字段等等。
字节码校验
这个阶段通过数据流和控制流分析,确保程序语义是合法的、符合逻辑的。比如:放置和使用操作栈时数据类型保证一致、保证跳转指令不会跳转到方法体以外的字节码指令上、保证方法体中的类型转换是有效的等等。
符号引用校验
这个阶段是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,它发生在解析步骤中,确保解析能正常执行,比如:符号引用中通过字符串描述的全限定名是否能找到对应的类、符号引用中的类字段方法的访问性是否可以访问当前类等等。
准备
在这个阶段里,为静态变量分配内存并设置静态变量初始值。这里说的初始值通常情况下,不是代码中写的初始值,而是数据类型的零值。代码中写的初始值,是在初始化阶段赋值的。如果是静态常量(被final修饰),这个阶段就会被直接赋值为代码中写的初始值。
解析
在这个阶段里,JVM把常量池内的符号引用替换为直接引用。符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,它和JVM实现的内存布局无关。直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄,它是和JVM实现的内存布局相关的。如果有了直接引用,那么引用的目标肯定在内存中存在。
解析主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符的符号引用进行,分别对应常量池的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info和CONSTANT_InvokeDynamic_info。
初始化
总结
对于面试,一定要有良好的心态,这位小伙伴面试美团的时候没有被前面阿里的面试影响到,发挥也很正常,也就能顺利拿下美团的offer。
小编还整理了大厂java程序员面试涉及到的绝大部分面试题及答案免费分享给大家,希望能帮助到大家,有需要的朋友可以看下面的免费领取方式!
↓↓↓
点击这里免费下载
a-p7)**
[外链图片转存中…(img-ZRU4FclT-1628678751231)]
[外链图片转存中…(img-4rm3iPtH-1628678751235)]
最后感谢大家的支持,希望小编整理的资料能够帮助到大家!也祝愿大家都能够升职加薪!