Java-类加载简单总结

325 阅读3分钟

类从被加载到虚拟机内存开始到卸载出内存,整个生命周期包括以下七个阶段:

类加载

一、类加载前5部分的功能或作用:

  1. 加载:根据查找路径找到相应的class文件,然后导入。

  2. 检查:检查加载的class文件的正确性。

  3. 准备;给类中的静态变量分配内存空间,赋以默认初始值。

  4. 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址。

  5. 初始化:对静态变量和静态代码块执行初始化工作。

二、类在什么情况下进行加载?

虚拟机对类的加载时机并没有明确的规定,是由具体的虚拟机实现的,当前明确规定了,在以下5种情况下(有且只有),类必须进行初始化(加载、验证、准备必须在初始化之前)。

这5种方式也被称为主动引用,除此之外的其他引用都不会触发初始化,称为被动引用。不会触发初始化,就不会执行静态代码块的方法。

  • 遇到new(使用new关键字创建实例对象的时候)、getstatic(读取一个静态变量,被final修饰,已在编译把结果放入常量池的静态变量除外)、putstatic(设置一个静态变量,被final修饰,已在编译把结果放入常量池的静态变量除外)或invokestatic(调用一个类的静态方法)这四条字节码指令的时候,如果类没有进行初始化,则需要先触发其初始化。
  • 使用java.lang.reflect方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发器初始化
  • 初始化一个类时,发现其父类没有进行初始化,则需要先触发父类的初始化。
  • 虚拟机启动的时候,用户需要指定一个执行的主类(包含main方法的类),虚拟机会先对初始化这个主类
  • 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法的句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。(使用场景未知)

三、验证

//Parent.java
public class Parent {
    static {
        System.out.println("我是父类的静态代码块");
    }

    public static String spName = "父亲名字";
}

//Child.java
public class Child extends Parent{
    static {
        System.out.println("我是子类的静态代码块");
    }

    public static String sCode = "001";

    public static final int sfAge = 10;
}

//test.java
public static void main(String[] args)
{
    System.out.println("**********不会初始化的情况**********");
    //引用类的静态常量不会触发定义常量的类的初始化,因为常量在编译阶段已经被放到常量池中
    System.out.println(Child.sfAge);
    //通过子类引用父类的静态字段,不会导致子类初始化
    System.out.println(Child.spName);

    System.out.println("**********会初始化的情况**********");
    //读取或者设置一个类的静态字段(被final修饰的除外)时
    System.out.println(Child.sCode);
}
    
结果:
**********不会初始化的情况**********
10
我是父类的静态代码块
父亲名字
**********会初始化的情况**********
我是子类的静态代码块
001

扩展

  • 执行类的静态方法时,static代码块也会执行,如果是连续执行静态方法的,static代码块只会执行一次。
  • 创建一个类的实例时,static代码块也会执行,如果是连续执行创建实例方法的,static代码块只会执行一次。
//Child.java
public class Child extends Parent{
    static {
        System.out.println("我是子类的静态代码块");
    }

    public static void SayHello()
    {
        System.out.println("大家好,我是Child对象");
    }
}

//test.java
Child.SayHello();
Child.SayHello();
Child.SayHello();
Child.SayHello();

//结果
我是父类的静态代码块
我是子类的静态代码块
大家好,我是Child对象
大家好,我是Child对象
大家好,我是Child对象
大家好,我是Child对象

参考

blog.csdn.net/u010805617/… blog.csdn.net/qiuchaoxi/a…