Java虚拟机类加载机制(二)——类加载的过程

在这里插入图片描述

加载

  • 将类的.class文件中的二进制数据读入到内存中
  • 将其放在运行时数据区的方法区内
  • 然后再内存中创建一个java.lang.Class对象用来封装类在方法区内的数据结构

简单地说,加载:在硬盘上查找并通过IO读入字节码文件

验证

目的:确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
主要分为四个检验部分:

  1. 文件格式验证:检验是否为class文件
  2. 元数据验证:验证是否符合Java语言规范
  3. 字节码验证:检验程序是否合法,符合逻辑
  4. 符号引用验证:保证该引用能够被访问到

要注意,验证阶段是非常重要的,但并不是一定必要的,对于反复使用和验证过的代码,可以通过使用-Xverify:none来关闭大部分类验证,来缩短验证时间。

准备

为类变量分配内存,设置类变量初始值
要注意的是:

  • 内存分配仅包括类变量(static),不包括实例变量,实例变量会在对象实例化时随对象分配在Java堆中
  • 初始值在通常情况下是0,并不是程序里的那个值。真正的赋值是在初始化时完成的。

解析

符号引用替换为直接引用,该阶段会把一些静态方法替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接的过程(程序加载期间完成),动态链接时在程序运行期间完成的符号引用替换为直接引用
符号引用:用符号来表示目标,符号可以是任意的字面量,要求无歧义
我们以字节码文档为例:
将一个简单的代码用javap命令生成字节码文件,内容如下

package Test;

public class Test {
	public int computer(){
		int a=1;
		int b=2;
		return a+b;
	}
	public static void main(String[] args) {
		Test test = new Test();
		int c = test.computer();
		System.out.println(c);
	}
}
Classfile /C:/Users/董润泽/workspace/Java虚拟机/src/Test/Test.class
  Last modified 2020-1-21; size 490 bytes
  MD5 checksum 1015aa0bd5fd4af85cc23a21ef42a1af
  Compiled from "Test.java"
public class Test.Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#18         // java/lang/Object."<init>":()V
   #2 = Class              #19            // Test/Test
   #3 = Methodref          #2.#18         // Test/Test."<init>":()V
   #4 = Methodref          #2.#20         // Test/Test.computer:()I
   #5 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #23.#24        // java/io/PrintStream.println:(I)V
   #7 = Class              #25            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               computer
  #13 = Utf8               ()I
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               SourceFile
  #17 = Utf8               Test.java
  #18 = NameAndType        #8:#9          // "<init>":()V
  #19 = Utf8               Test/Test
  #20 = NameAndType        #12:#13        // computer:()I
  #21 = Class              #26            // java/lang/System
  #22 = NameAndType        #27:#28        // out:Ljava/io/PrintStream;
  #23 = Class              #29            // java/io/PrintStream
  #24 = NameAndType        #30:#31        // println:(I)V
  #25 = Utf8               java/lang/Object
  #26 = Utf8               java/lang/System
  #27 = Utf8               out
  #28 = Utf8               Ljava/io/PrintStream;
  #29 = Utf8               java/io/PrintStream
  #30 = Utf8               println
  #31 = Utf8               (I)V
{
  public Test.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public int computer();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iload_1
         5: iload_2
         6: iadd
         7: ireturn
      LineNumberTable:
        line 5: 0
        line 6: 2
        line 7: 4

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class Test/Test
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #4                  // Method computer:()I
        12: istore_2
        13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: iload_2
        17: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
        20: return
      LineNumberTable:
        line 10: 0
        line 11: 8
        line 12: 13
        line 13: 20
}
SourceFile: "Test.java"

可以看到,上面有一些“#数字”:
在这里插入图片描述
这其实就是生成的符号,对于后面的解释,例如“#7:#8”即指“#1”这个符号引用了“#7”和“#8”的内容
这即为符号引用
直接引用:引用的是目标的一个地址

初始化

对类的静态变量初始化为指定的值,执行静态代码块
同准备阶段的赋初始值不同!
在博客 Java虚拟机类加载机制(一)——类加载的时机已介绍,可参考理解。

发布了45 篇原创文章 · 获赞 14 · 访问量 2462

猜你喜欢

转载自blog.csdn.net/qq_44357371/article/details/104072447