Java类进行"初始化"的时机

类进行"初始化"的必须情况(有且仅有五种情况)

1.遇到new,getstatic,putstatic或invokestatic这4条字节码指令时.
分别对应常见的4种场景,new关键字实例化对象,读取或设置类的静态字段(不包括被final修饰的字段,已在编译期把结果放入常量池中),调用类静态方法时。

public class Main {
    public static void main(String[] args) {
    }
    static class Test{
        static {
            System.out.println("Init Test");
        }
        static int x = 3;
        final static int y = 4;
        static void print() {
            System.out.println("has inited?");
        }
}

在main函数中分别置于以下语句,观察是否执行static代码段。

new Test(); //触发初始化
System.out.println(Test.x);  //触发初始化
Test.x = 4;  //触发初始化
Test.print();  //触发初始化
System.out.println(Test.y);  //不触发初始化
  1. 利用反射对类进行调用时。

在main函数中置于下面语句时,观察是否执行static代码段。

       try { 
            Test.class.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        for (Field field : Test.class.getDeclaredFields()) {
            if (field.getName().equals("x")) {
                try {
                    System.out.println(field.get(Test.class));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
       for (Field field : Test.class.getDeclaredFields()) {
            if (field.getName().equals("y")) {
                try {
                    System.out.println(field.get(Test.class));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

不管是实例化,还是访问static变量,或者是访问static final变量,都会触发初始化。但仅仅是访问field时,置于以下语句时,不会触发初始化。

for (Field field : Test.class.getDeclaredFields()){
    System.out.println(field.getName());
}
  1. 初始化一个类时,若父类未初始化,则先初始化父类.
public class Main {

    public static void main(String[] args) {
        
    }

    static class Fa {
        static {
            System.out.println("Init Fa");
        }
        static int fax = 3;
        static final int fay = 4;
    }

    static class Test extends Fa{
        static {
            System.out.println("Init Test");
        }
        static int x = 3;
        final static int y = 4;
        static void print() {
            System.out.println("has inited?");
        }
    }
}

在main函数置于以下语句

System.out.println(Test.x); //初始化父类,然后初始化子类
System.out.println(Test.fax); //初始化父类,不初始化子类
System.out.println(Test.fay); //不初始化父类,也不初始化子类
  1. 虚拟机启动时,主类(包含main方法的那个类),先初始化此类。
public class Main {
    static {
        System.out.println("Init Main");
    }
    public static void main(String[] args) {
        try {
            Test.class.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    static class Fa {
        static {
            System.out.println("Init Fa");
        }
        static int fax = 3;
        static final int fay = 4;
    }

    static class Test extends Fa{
        static {
            System.out.println("Init Test");
        }
        static int x = 3;
        final static int y = 4;
        static void print() {
            System.out.println("has inited?");
        }
    }
}
/*
打印结果:
Init Main
Init Fa
Init Test
*/

  1. jdk1.7 通过方法句柄的方式动态执行方法或者修改访问static变量时。
public class Main {
    static {
        System.out.println("Init Main");
    }
    public static void main(String[] args) {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        try {
            MethodHandle methodHandle = lookup.findStatic(Test.class, "print", MethodType.methodType(void.class));
            methodHandle.invoke();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

    static class Fa {
        static {
            System.out.println("Init Fa");
        }
        static int fax = 3;
        static final int fay = 4;
    }

    static class Test extends Fa{
        static {
            System.out.println("Init Test");
        }
        static int x = 3;
        final static int y = 4;
        static void print() {
            System.out.println("has inited?");
        }
    }
}

你可能感兴趣的:(Java类进行"初始化"的时机)