类初始化和对象初始化之间的差别

有一个类A:

public class A {
    static {
        System.out.println("A类静态块");
    }

    public A() {
        System.out.println("A类的构造方法");
    }
}

再创建一个类B,继承类A

public class B extends A {
    static {
        System.out.println("B类静态块");
    }

    public B() {
        System.out.println("B类的构造方法");
    }
}

创建个main方法测试下:

   public static void main(String[] args) {
        System.out.println("第一次new B对象,赋值给变量a");
        A a = new B();
        System.out.println("第二次new B对象,赋值给a变量");
        a = new B();
    }

运行结果如下:
在这里插入图片描述

这里可以发现在第一次new B对象时,调用了A的静态块->B的静态块->A类的构造方法->B类的构造方法
而第二次new B对象时,只调用了A类的构造方法->B类的构造方法

在第一次new B对象时,其实可以这样说,在运行期,首次引用B类时,B类会被类加载子系统加载,经过加载->链接->初始化这些步骤,把B类的信息加载进方法区,这时先进行的是类的初始化步骤,又因为B是A的子类,所以A要先于B被初始化,这里可以简单的想象成,要先有爸爸才能有儿子,因此就出现了A的静态块->B的静态块这个步骤。然后因为我们真正做的是要实例化出B对象,所以肯定是要调用B的构造方法的,又因为B是A的子类,所以会先调用A的构造方法,然后再继续调用B的构造方法,因此就出现了A类的构造方法->B类的构造方法这个步骤。

在第二次new B对象时,这时由于B类的元数据等信息已经存入了方法区内,或者可以直接理解成B类已经被加载了,同时也还没被卸载,由于被static修饰的代码块是属于类的,因此不需要再加载一次,所以这时候直接先调用A的构造方法,然后再继续调用B的构造方法就好了,所以第二次new B对象的步骤是A类的构造方法->B类的构造方法。

总结

通过上述案例可以了解到,类的初始化,只会执行一次,通过static代码块只执行一次就可以验证这想法,而对象的初始化,每次都会调用一次构造方法,从A类和B类的构造方法分别出现了两次就可验证这想法。

原创文章 358 获赞 387 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_38106322/article/details/105535640