类的加载、连接和初始化

一.JVM和类

package JVM;

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

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

package JVM;

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

 

以上程序引出以下认识:

/**
*一.同一个JVM的所有线程,所有变量都处在同一个进程里
* 它们都使用该JVM进程的内存区
*二.JVM进程终止情况
* 程序运行到最后正常结束
* 程序运行使用System.exit()或Runtime.getRuntime().exit()代码处结束程序
* 程序执行过程中遇到未捕捉的异常或错误而结束
* 程序所在平台强制结束了JVM进程
*三.这三个代码ATest和BTest是在两个不同的JVM进程中运行,所以ATest类修改会消失
* 说明了JVM进程结束,该进程在内存中的状态将会丢失
*/


二.类的加载

1.系统还未被加载到内存中、则系统会通过加载、连接、初始化三个步骤来对该类进行初始化

2.类加载:将类的class文件读入内容,并创建一个java.lang.Class对象

3.JVM提供类加载器(程序运行的基础)-->完成类加载

4.类加载器的种类

  •   从本地文件系统加载class文件(绝大部分程序的类加载方式)
  •   从JAR加载class文件
  •  通过网路加载class文件
  •  把一个java源文件动态编译,并执行加载

java虚拟机允许系统预先加载某些类


三.类的连接

类加载后,系统为止生成一个对应的class文件-->进入连接阶段

类的连接:类的二进制数据合并到JRE中,类连接的三个阶段

  • 验证结构:被加载类内部结构是否正确
  • 分配内存:为类的类变量分配内存,并设置默认初始值
  • 解析符号:将类的二进制数据中的符号引用替换成直接引用

四.类的初始化

类的初始化:虚拟机负责对类进行初始化,主要就是对类变量进行初始化

类变量指定初始化值有两种方式:

  • 声明类变量指定初始值
  • 使用静态初始化块为类变量指定初始化值
package JVM;

public class Test {
    //声明变量a时指定初始值
    static int a = 5;
    static int b;
    static int c;
    
    {
        //使用静态初始化块为变量b指定初始值
        b=6;
    }
}

JVM初始化一个类包含如下几个步骤:

  • 类还未被加载和连接
  • 类的直接父类还没有被初始化,则先初始化其直接父类
  • 假如类中有初始化语句,则系统依次执行这些初始化语句

当执行第二个步骤时,系统对直接父类的初始化步骤也遵循此步骤1~3


五.类初始化的时机

①创建类的实例

②调用某个类的类方法

访问某个类或接口的类变量,或为该类变量赋值

④使用反射方式来强制创建某个类或接口对应的java.lang.class对象.例如代码:Class.forName("Person"),这行代码初始化还未初始化的类

⑤初始化某个类的子类

⑥直接用java.exe命令来运行某个主类

⑦特别情形:final型的类变量,如果该类变量的值在编译时就可以确定下来,该类变量相当于"宏变量".java编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化

package JVM;

class MyTest{    
    static 
    {
        System.out.println("静态初始化块....");
    }
    //使用一个字符串直接量为static final的类变量赋值
    static final String  compileConstant = "疯狂java讲义";
}
public class CompileConstantTest {
    public static void main(String[] args) {
        //访问、输出MyTest中的compileConstant类变量
        System.out.println(MyTest.compileConstant);  //①
    }
}
①处代码当做"宏变量"处理,不会初始化

原文地址:https://www.cnblogs.com/zjm1999/p/10298485.html