jvm读取静态字段

类初始化规则

虚拟机规范则严格规定了有且只有5种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要
在此之前开始):

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

类初始化需要做的就是执行静态代码块,完成静态变量的赋值
静态字段、静态代码段,字节码层面会生成clinit方法

读取静态字段

test1

public class Test_1 {
    
    
    public static void main(String[] args) {
    
    
        Test_1_Enum v = Test_1_Enum.V;

        System.out.printf(Test_1_B.str);
    }

    //输出
//    Enum Static Block
//    A Static Block
//    A str
    //jvm中类的加载是懒加载的,并没有创建Test_1_B的对象,但是经过了父类的对象,A里面已经有str没必要加载B
}

class Test_1_A {
    
    
    public static String str = "A str";

    static {
    
    
        System.out.println("A Static Block");
    }
}

class Test_1_B extends Test_1_A {
    
    
    static {
    
    
        System.out.println("B Static Block");
    }
}

enum Test_1_Enum {
    
    
    V;

    static {
    
    
        System.out.println("Enum Static Block");
    }
}

test2

public class Test_2 {
    
    

    public static void main(String[] args) {
    
    
        System.out.printf(Test_2_B.str);

        //输出
        // A Static Block
        //B Static Block
        //B str
        //B里面有str需要加载B类,A是B的父类也需要加载
    }
}

class Test_2_A {
    
    
    static {
    
    
        System.out.println("A Static Block");
    }
}

class Test_2_B extends Test_2_A {
    
    
    public static String str = "B str";

    static {
    
    
        System.out.println("B Static Block");
    }
}

test3

public class Test_3 {
    
    

    public static void main(String[] args) {
    
    
        System.out.printf(Test_3_B.str);

        //输出
//        A Static Block
//        B Static Block
//        B str
      //B里面有str需要加载B类,A是B的父类也需要加载
    }
}

class Test_3_A {
    
    
    public static String str = "A str";

    static {
    
    
        System.out.println("A Static Block");
    }
}

class Test_3_B extends Test_3_A {
    
    
    public static String str = "B str";

    static {
    
    
        System.out.println("B Static Block");
    }
}

test4

public class Test_4 {
    
    

    public static void main(String[] args) {
    
    
        Test_4_A arrs[] = new Test_4_A[1];

        System.out.println("end");
        //输出end 只是定义个一个数组类型,数组类是jvm运行时创建的,A类不会被加载
    }
}

class Test_4_A {
    
    
    static {
    
    
        System.out.println("Test_4_A Static Block");
    }
}

test5

public class Test_5 {
    
    

    public static void main(String[] args) {
    
    
        Test_5_A obj = new Test_5_A();

        System.out.println("end");
        //输出
//       Test_5_A Static Block
//                end
        //new 了一个新的对象需要加载A类,执行静态代码块
    }
}

class Test_5_A {
    
    
    static {
    
    
        System.out.println("Test_5_A Static Block");
    }
}

test6

public class Test_6 {
    
    

    public static void main(String[] args) {
    
    
        System.out.println(Test_6_A.str);

        //输出 A str
        //final是常量,将常量写入了stringTable常量池。没有加载A类
    }
}

class Test_6_A {
    
    

    public static final String str = "A Str";

    static {
    
    
        System.out.println("Test_6_A Static Block");
    }


//    public static final String str = "A Str";
}

test7

public class Test_7 {
    
    

    public static void main(String[] args) {
    
    
        System.out.println(Test_7_A.uuid);
        //输出
        //Test_7_A Static Block
        //3afa6977-6ca5-4267-90aa-022ee34ee740
      //uuid是动态生成,无法写入常量池,所以需要加载,jvm底层应该是做了特殊处理
    }
}

class Test_7_A {
    
    
    public static final String uuid = UUID.randomUUID().toString();

    static {
    
    
        System.out.println("Test_7_A Static Block");
    }
}

test8

public class Test_8 {
    
    

    static {
    
    
        System.out.println("Test_8 Static Block");
    }

    public static void main(String[] args) throws ClassNotFoundException {
    
    
        Class<?> clazz = Class.forName("com.demo.hxl.classload.Test_8_A");

        System.out.println("end");
    }
}

class Test_8_A {
    
    
    static {
    
    
        System.out.println("Test_8_A Static Block");
    }
}
//输出
//Test_8 Static Block
//Test_8_A Static Block
//end
//反射也会加载静态代码块

test9

扫描二维码关注公众号,回复: 13132852 查看本文章
public class Test_21 {
    
    

    public static void main(String[] args) {
    
    
        Test_21_A obj = Test_21_A.getInstance();

        System.out.println(Test_21_A.val1);
        System.out.println(Test_21_A.val2);
    }
}

class Test_21_A {
    
    

    public static int val1 = 0;
    public static int val2 = 1;

    public static Test_21_A instance = new Test_21_A();

     Test_21_A() {
    
    
        val1++;
        val2++;
    }

    public static Test_21_A getInstance() {
    
    
        return instance;
    }
}
//输出
//1
//2
//代码执行的顺序和定义的顺序是保持一致的

test10

public class Test_22 {
    
    

    public static void main(String[] args) {
    
    
        Test_22_A obj = Test_22_A.getInstance();

        System.out.println(Test_22_A.val1);
        System.out.println(Test_22_A.val2);
    }
}

class Test_22_A {
    
    

//    public static int val1;

    public static Test_22_A instance = new Test_22_A();

     Test_22_A() {
    
    
        val1++;
        val2++;
         System.out.println("val1 = " + val1 + "\t val2 = " + val2);
    }

    public static int val1 = 2;
    public static int val2 = 0;

    public static Test_22_A getInstance() {
    
    
        return instance;
    }
}
//输出
//val1 = 1	 val2 = 1
//        2
//        0
//
//val1和val2初始化是都为0 ,构造方法时++,变成都为1,然后被覆盖```

猜你喜欢

转载自blog.csdn.net/hxl2585530960/article/details/114559822