欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JVM中类的初始化时机

程序员文章站 2022-05-21 19:27:59
...

只有对类进行主动引用,才会触发其初始化方法,而除此之外的引用方式称之为被动引用,不会触发其初始化方法

1.主动引用

这里先定义一个Utils(名字随便起的,不要见怪)作为被测试类

package day12;

/**
 * @author :weihuanwen
 * @date :Created in 2019/5/23 00:14
 * @description :
 * @version: 1.0
 */
public class Utils {
    //定义静态final变量
    public static final int sfVar = 100;
    //定义实例变量
    public int instanceVar = 1;
    //定义静态变量
    public static int staticVar = 10;
    //通过静态代码块是否执行验证此类是否加载
    static {
        System.out.println("Utils类被加载!");
    }
    /**
     * 定义静态方法
     */
    public static void staticMethod(){
        System.out.println("执行了静态方法!");
    }
    /**
     * 定义成员方法
     */
    public void instanceMethod(){
        System.out.println("执行了成员方法");
    }
}

①设置静态成员变量时

package day12;

public class test01 {
    public static void main(String[] args) {
        Utils.staticVar = 10;
    }
}

输出结果显示:

Utils类被加载!

②调用静态方法时

package day12;

public class test01 {
    public static void main(String[] args) {
        Utils.staticMethod();
    }
}

输出结果显示:

Utils类被加载!
执行了静态方法!

③实例化对象时

package day12;

public class test01 {
    public static void main(String[] args) {
        Utils utils = new Utils();
    }
}

输出结果显示:

Utils类被加载!

④读取静态成员变量时

package day12;

public class test01 {
    public static void main(String[] args) {
        System.out.println(Utils.staticVar);
    }
}

输出结果显示:

Utils类被加载!

10

⑤反射调用时

package day12;

public class test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("day12.Utils");
    }
}

输出结果显示:

Utils类被加载!

⑥初始化子类时,会先初始化其父类

package day12;
/**
 * 父类
 */
public class SuperClass {
    static {
        System.out.println("父类被加载!");
    }
}
package day12;
/**
 * 子类
 */
public class SubClass extends SuperClass{
    static {
        System.out.println("子类被加载!");
    }
}
package day12;

public class test01 {
    public static void main(String[] args){
       new SubClass();
    }
}

输出结果显示:

父类被加载!
子类被加载!

⑦Java虚拟机启动时被标明为启动类的类(含main()方法的类)

package day12;

public class Mark {
    static {
        System.out.println("标记类Mark被加载!");
    }

    public static void main(String[] args) {
        //这里不写代码,直接自行该main()方法
    }
}
class ReferFirst{
    static {
        System.out.println("第一个参照类被加载!");
    }
}
class ReferSecond{
    static {
        System.out.println("第二个参照类被加载!");
    }
}

输出结果显示:

标记类Mark被加载!

2.被动引用:

除了以上七种情况外的都尊徐被动引用,这里只介绍几种被动引用

①通过子类引用父类的静态字段,不会导致子类的初始化

package day12;
/**
 * 父类
 */
public class SuperClass {
    public static int staticVar = 10;
    static {
        System.out.println("父类被加载!");
    }
}
package day12;
/**
 * 子类
 */
public class SubClass extends SuperClass{
    static {
        System.out.println("子类被加载!");
    }
}
package day12;

public class test01 {
    public static void main(String[] args){
        System.out.println(SubClass.staticVar);
    }
}

输出结果显示:

父类被加载!
10

②读取static final 修饰的变量时,不会导致类的初始化

package day12;

public class test01 {
    public static void main(String[] args){
        System.out.println(Utils.sfVar);
    }
}

输出结果显示:

100

****常量在编译阶段会存入调用类的常量池中,本质没有直接引用到定义的常量类中,因此不会触发定义的常量类初始化

③通过数组定义来引用,不会导致类的初始化

package day12;

public class Person {
    static {
        System.out.println("Person类被加载!");
    }
}
package day12;

public class test01 {
    public static void main(String[] args){
        Person[] personarr = new Person[10];
    }
}

输出结果显示:

无输出结果

④通过集合定义来引用,不会导致类的初始化(道理同③)