详解Java 类的加载、连接和初始化

2020-06-23 13:02 来源:易采站长站 作者:丽君 点击: 评论:

A-A+

原标题:详解Java 类的加载、连接和初始化

系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类。本节将会详细介绍类加载、连接和初始化过程中的每个细节。

JVM 和类

当调用 java 命令运行某个 Java 程序时,该命令将会启动一个 Java 虚拟机进程,不管该 Java 程序有多么复杂,该程序启动了多少个线程,它们都处于该 Java 虚拟机进程里。正如前面介绍的,同一个 JVM 的所有线程、所有变量都处于同一个进程里,它们都使用该 JVM 进程的内存区。当系统出现以下几种情况时,JVM 进程将被终止。

程序运行到最后正常结束。 程序运行到使用 system.exit() 或 Runtime.getRuntime().exit() 代码处结束程序。 程序执行过程中遇到未捕获的异常或错误而结束。 程序所在平台强制结束了 JVM 进程。

从上面的介绍可以看出,当 Java 程序运行结束时,JVM 进程结束,该进程在内存中的状态将会丢失。下面以类的类变量来说明这个问题。下面程序先定义了一个包含类变量的类。

public class A {
  // 定义该类的类变量
  public static int a = 6;
}

上面程序中的粗体字代码定义了一个类变量a,接下来定义一个类创建A类的实例,并访问A对象的类变量a。

public class ATest1 {
  public static void main(String[] args) {
    // 创建A类的实例
    A a = new A();
    // 让a实例的类变量a的值自加
    a.a++;
    System.out.println(a.a);
  }
}

下面程序也创建A对象,并访问其类变量a的值。

public class ATest2 {
  public static void main(String[] args) {
    // 创建A类的实例
    A b = new A();
    // 输出b实例的类变量a的值
    System.out.println(b.a);
  }
}

在 ATest1.java 程序中创建了A类的实例,并让该实例的类变量a的值自加,程序输出该实例的类变量a的值将看到7,相信读者对这个答案没有疑问。关键是运行第二个程序 ATest2 时,程序再次创建了A对象,并输出A对象类变量的a的值,此时a的值是多少呢?结果依然是6,并不是7。这是因为运行 ATest1 和 ATest2 是两次运行 JVM 进程,第一次运行 JVM 结束后,它对A类所做的修改将全部丢失——第二次运行 JVM 时将再次初始化A类。

注意:两次运行 Java 程序处于两个不同的 JVM 进程中,两个 JVM 之间并不会共享数据。

类的加载

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三个步骤来对该类进行初始化。如果没有意外,JVM 将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或类初始化。

类加载指的是将类的 class 文件读入内存,并为之创建一个 java.lang.Class 对象,也就是说,当程序中使用任何类时,系统都会为之建立一个 java.lang.Class 对象。

【易采站长站编辑:秋军】