Java类加载机制


类的生命周期

加载-验证-准备-解析-初始化-使用-卸载

1 加载阶段

把.class二进制数据读到内存中,并放到方法区,然后在堆中创建一个Java.lang.Class对象,这个对象就是用来封装类在方法区的数据结构的。
所以,类加载机制的最终产物是:在堆中创建了java.lang.Class对象,这个对象提供了访问方法区内部数据结构的接口。

2 验证阶段

这个主要就是验证包的签名等

3 准备阶段

为静态变量分配内存,并设置初始值。
内存分配动作发生在方法区的,在准备阶段,给类成员进行初始化。

类型 初始化值
String null
Object null
int 0

4 解析阶段

将符号引用转成直接引用
说白了,就是,将变量换成内存中真实地址,都将高级的东西解析为机器识别的底层东西。

5 初始化(最重要的)

5-1 初始化2种方式

初始化有生命类变量和静态代码块2种方式,它们的优先级相同,谁在前面谁先来。

static int age = 20;
    static{
        System.out.println("hello,world");
        System.out.println(age);
    }

6 初始化的触发几种情况

6-1 创建类对象的时候

  • new
  • 反射
  • 对象的反序列化

6-2 调用类的某个静态方法

package com.siyu;

public class Claloader {
    static int age = 20;
    static{
        System.out.println("hello,world");
        System.out.println(age);
    }

    public static void getName(){
        String name = Thread.currentThread().getName();
        System.out.println(name);
    }
}
package com.siyu;

public class Test {
    public static void main(String[] args) {
//        调用类的某个静态方法,触发类的初始化
        Claloader.getName();
//        hello,world
//        20
//        main
    }
}

6-3 调用某个类或接口中的类变量

package com.siyu;

public class Claloader {
    static int age = 20;
    static{
        System.out.println("hello,world");
        System.out.println(age);
    }

    public static void getName(){
        String name = Thread.currentThread().getName();
        System.out.println(name);
    }
}

package com.siyu;

public class Test {
    public static void main(String[] args) {
//        调用类的某个静态方法,触发类的初始化
        int age = Claloader.age;
//        hello,world
//        20
    }
}


6-4 调用子类静态变量,引父类初始化

package com.siyu;

public class Claloader {
    static int age = 20;
    static{
        System.out.println("hello,world");
        System.out.println(age);
    }

    public static void getName(){
        String name = Thread.currentThread().getName();
        System.out.println(name);
    }
}

class Sub extends Claloader{
    static String name = "nezha";
    static {
        System.out.println("这是子类的静态代码块");
    }
}

package com.siyu;

public class Test {
    public static void main(String[] args) {

        int age = Sub.age;
//        hello,world
//        20
    }
}


6-5 直接用java.exe运行某个类

7 注意的是

  • 子类引用父类静态变量,不会引发子类初始化
  • 通过数组定义引用类,不会引起类初始化
  • 使用final修饰的为常量,不会引起初始化

相关