JVM学习(五)- 接口初始化规则与类加载器准备阶段和初始化阶段

JVM学习(五)- 接口初始化规则与类加载器准备阶段和初始化阶段

我们需要的是从案列里面寻找答案所以我一开始时写的案列

实列1:

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

        System.err.println(MyChild5.b);
     
    }
}
interface MyParent5{
    public static final int a=3;
}
interface MyChild5 implements MyParent5{
    public static final  int b=new Random().nextInt(5);
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCKpZUMF-1580892304028)(E:\Typora\图片\Mtest5.1.png)]

​ 这个结果根据代码来推断只能证明了我们初始化了MyChild5类,应该接口中属性默认Public Static Final本应该进入MyTest5的常量池当中,但是MyChild5用到了new Random().nextInt(5);他是运行期间固定常量所以没有进入MyChild5的常量池当中所以MyChild5初始化了,这个是我上一篇写到过。

这里我们就需要改一下代码:

实列1更改代码:

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

      System.err.println(MyChild5.b);
       

    }
}
interface MyParent5{
    public static final Thread thread=new Thread(){
        {
            System.err.println("MyParent5 invoked");
        }
    };
}
class MyChild5 implements MyParent5{
    public static  int b=5;
}


运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r3oWi3UA-1580892304028)(E:\Typora\图片\Mtest5.2.png)]

判断MyParent5初始化代码:

    public static final Thread thread=new Thread(){
        {
            System.err.println("MyParent5 invoked");
        }
    };

​ 这一串代码的作用就是MyParent5被初始化了这个thread会被赋值这是初始化阶段,那么准备阶段就是吧累的静态的变量分配空间这里已经过了准备阶段,如果有初始化阶段那么System.err.println(“MyParent5 invoked”);这句话就会被执行出来。

那么我们的总结:

/**
 * 当一个接口初始化时,并不要求其附接口都完成初始化
 * 只有在真正使用到父接口的时候(如引用接口中所定义的常量时),才会初始化
 */

准备阶段的测试

实列3

public class MyTest6 {
    public static void main(String[] args) {
        Singleton singleton=Singleton.getSingleton();
        System.err.println("counter1:"+Singleton.counter1);
        System.err.println("counter2:"+Singleton.counter2);
    }

}
class Singleton{
    public static int counter1;
    public static int counter2;
    private static Singleton singleton=new Singleton();
    private Singleton(){
        counter1++;
        counter2++;
    }
    public static Singleton getSingleton(){
        return singleton;
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ZJdHk7Y-1580892304029)(E:\Typora\图片\Mtest6.1.png)]

​ 这个结论比较好理解这里的代码JVM会在你可能用到的类预先加载一边,准备阶段就会给counter1,counter2会设置默认值为0,直到初始化阶段当没有正确值的时候就是默认值接着就是Singleton()构造方法里面两个属性++,getSingleton()方法返回出去Singleton这个对象输出的两个1。

实列3代码更改1.0:

public class MyTest6 {
    public static void main(String[] args) {
        Singleton singleton=Singleton.getSingleton();
        System.err.println("counter1:"+Singleton.counter1);
        System.err.println("counter2:"+Singleton.counter2);
    }

}
class Singleton{
    public static int counter1;
    private static Singleton singleton=new Singleton();
    private Singleton(){
        counter1++;
        counter2++;
    }
    public static int counter2=0;
    public static Singleton getSingleton(){
        return singleton;
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLkQuVdr-1580892304029)(E:\Typora\图片\Mtest6.2.png)]

​ 这里的代码就很好理解根据上面说的流程,我们更改counter2的位置以及赋予了一个值;这个变量时根据初始化赋予的正常值所以会出书counter2:0,接下来我们再来改一下代码;

实列3代码更改1.1:

public class MyTest6 {
    public static void main(String[] args) {
        Singleton singleton=Singleton.getSingleton();
        System.err.println("counter1:"+Singleton.counter1);
        System.err.println("counter2:"+Singleton.counter2);
    }

}
class Singleton{
    public static int counter1;
    private static Singleton singleton=new Singleton();
    private Singleton(){
        counter1++;
        counter2++;
    }
    public static int counter2;
    public static Singleton getSingleton(){
        return singleton;
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PJJBCtov-1580892304030)(E:\Typora\图片\Mtest6.3.png)]

这里我们吧counter2=0;改成counter2输出的结果居然跟上面的代码结果不一样接下来我们来总结一下。

  • 准备:为类变量分配内存,设置默认值。但是在到达初始化之前,类变量都没 有初始化为正确的初始值。

  • 初始化:为类变量赋予正确的初始值

很明显准备阶段是在初始化阶段前面所以准备阶段过后counter2++已经为1值代码往下到public static int counter2;这个变量的时候他初始化了但是他没有正确的初始值所以唯一

发布了7 篇原创文章 · 获赞 1 · 访问量 297

猜你喜欢

转载自blog.csdn.net/weixin_44281696/article/details/104184844