学习jvm的第三天

1.关于接口存在的继承关系的时候是否会被初始化

首先献上代码

package com.example.demo.test;
public class MyTest4 {
    public static void main(String[] args){
        System.out.println(MyChild4.b);
    }
}

interface MyParent4{
    public static int a=5;
}
interface MyChild4 extends MyParent4{
    public static int b=6;
}

查看执行结果

当我将Myparent4生成的class文件删除之后,再去执行发现正常。

总结:当一个接口在初始化的时候,并不要求其父接口都完成了初始化,只有在真正使用父接口的时候(如引用接口中定义的常量时)才会初始化。

对于一个接口来说,它的属性就是final修饰的,对于类型来说就不是

对于接口来说,只有真正使用的时候才会被初始化,对于类来说不管有没有被使用,它的父类都要被初始化

2.关于类初始化的执行顺序问题

package com.example.demo.test;
public class MyTest5 {
    public static void main(String[] args){
        Singleton singleton=Singleton.getInstance();
        System.out.println(singleton.counter1);
        System.out.println(singleton.counter2);
    }
}

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

    private Singleton(){
        counter1++;
        counter2++;
    }


    public static Singleton getInstance(){
        return singleton;
    }
}

执行结果就是11

但是如果调整下顺序为

package com.example.demo.test;
public class MyTest5 {
    public static void main(String[] args){
        Singleton singleton=Singleton.getInstance();
        System.out.println(singleton.counter1);
        System.out.println(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 getInstance(){
        return singleton;
    }
}

它的执行结果为1,0

总结:在加载这个类的时候都会赋予属性一个默认的值,如果该属性为int类型,那么将首先赋予默认值0,然后按照自上而下的执行顺序去执行,由于counter2的定义在后面所以,首先在加载的时候已经是++了,然偶再去初始化就是设置了0,结果自然就是1,0。

3.final定义的常量,类,方法有什么区别。

  1.final定义的类,将不能被继承

   2.final定义的方法,将不能被重写

   3.final定义的属性,将不能被重新赋值

4.类加载器

  类加载器一共有两种

    1.java虚拟机自带的加载器

             根类加载器(Bootstrap)

              扩展类加载器(Extension)

              系统(应用类加载器)(System)

     2.用户自定义的类加载器

              java.lang.ClassLoader的子类

              用户可以定制类的加载方式

5.类的加载

     JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到.class文件缺失或者存在错误,类加载器必须在程序首次使用该类时才报告错误。

    如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。

    类加载器在类加载之前就预先加载。

6.类的验证

    类被加载后,就进入连接阶段,连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行环境中去。

7.类的验证

    类的验证内容:类文件的结构检查,语义的检查,字节码的验证,二进制兼容性的验证

8.类的准备

     在准备阶段,JVM为类的静态变量分配内存,并设置默认的初始值。

       

9.类的初始化

      在初始化阶段,JVM执行类的初始化语句,为类的静态变量赋予初始值。

      假如这个类还没有被加载和连接,那就先进行加载和连接。

      假如类存在父类,并且这个父类还没有被初始化,那就先初始化父类。

      假如类中存在初始化语句,那就一次执行这些初始化语句。

       假如存在接口:

                   1.在初始化一个类时,并不会先初始化它所实现的接口

                    2.在初始化一个接口时,并不会先初始化它的父类接口

        因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量时,才会导致接口的初始化。

10.类的初始化时机

         调用ClassLoader类和loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

11.双亲委派机制

         一个类加载器需要加载类,那么首先将这个请求委派给父类加载器去加载,每一层都是如此,一直递归到顶层也就是根类加载器去加载,当根类加载器无法完成加载的时候,就去委托它的子类去加载,也就是扩展类加载器去加载,当扩展类加载器无法完成加载的时候,再去委托它的子类系统类加载器,每一层都是如此,直到最后被加载或者加载失败报错为止。

原创文章 46 获赞 24 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_39892293/article/details/105634145