初始化阶段是最重要的
类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。
程序员可以使用 Java 代码扩展的不同的渠道:
类加载器在加载完类后,Java 虚拟机会将字节码中的信息保存到方法区中
<aside> 💡 方法区只是一个虚拟的概念,真正的实现是永久代或者元空间。
</aside>
生成一个 InstanceKlass 对象,保存类的所有信息,里面还包含实现特定功能比如多态的信息
同时,Java 虚拟机还会在堆中生成一份与方法区中数据类似的 java.lang.Class
对象,作用是在 Java 代码中去获取类的信息以及存储静态字段的数据(JDK 8 之后)
<aside> 💡 为什么类要同时加载到方法区和堆区,不能只加载一个?
</aside>
<aside> 💡 如何查看内存中的对象?
程序启动后出现可视化界面。输入 Java 进程的 ID 即可查看
</aside>
**验证:**内容是否满足《Java 虚拟机规范》
文件格式验证(魔数)
主次版本号是否满足当前 Java 虚拟机要求
元信息验证,例如类必须有父类
验证程序执行指令的语义,比如方法内的指令执行中跳转到不正确的位置
**准备:**给静态变量赋初值
赋初值为 0,变为 1 的过程发生在初始化过程中(除非变量用 final
修饰)
不同类型有不同的默认值,赋初值的作用是为了避免打印出乱七八糟的数据:
**解析:**将常量池中的符号引用替换为直接引用。符号引用就是在字节码文件中使用编号来访问常量池中的内容,而直接饮用不使用编号,而是使用内存中的地址访问具体的数据。
final
修饰的并且等号右边是常量不会触发初始化