java类的初始化顺序以及注意事项

不积跬步无以至千里

探讨内容目录

  1. 一个类的初始化顺序,由简至繁的讲解。
  2. 两个类的初始化,子类初始化的时候,父类是如何行动的。

一个类的初始化

  1. 这个类包含了普通变量,静态变量,普通代码块,静态代码块,构造器,以及普通方法。
public class OneClass {
    //普通属性
    public String a = "普通变量声明时候的值";
    //静态属性
    public static String staticB = "静态变量声明时候的值";
    //代码块
    {
        System.out.println("此时此刻普通代码块: " + a);
        a = "普通代码块中的值";
        System.out.println("此时此刻普通代码块: " + staticB);
        staticB = "静态代码在普通代码块中的值";
    }
    //静态代码块
    static {
        System.out.println("此时此刻静态代码块: " + staticB);
        staticB = "静态代码在普通代码块中的值";
    }
	
	//构造方法
    public OneClass(String a, String staticB){
        this.a = a;
        OneClass.staticB = staticB;
        System.out.println("构造方法执行了");
    }

    @Override
    public String toString() {
        return "OneClass{" +
                "a='" + a + '\'' +
                "staticB='" + staticB + '\'' +
                '}';
    }
}

class Test{
    public static void main(String[] args) {
        String s = new OneClass("a", "staticB").toString();
        System.out.println(s);
    }
}

结果分析

在这里插入图片描述
毫无疑问,变量肯定是首先被初始化的(这个可以自己验证:写一个类,然后把该类作为另一个类的属性并且实例化),然后根据结果可查看到首先执行的是静态代码块,其次是普通代码块,接着是构造方法!构造方法中的初始化覆盖了前面两种代码块的值,所以最后打印输出各属性的值是用户传入的参数。

两个类的初始化


public class TwoClass {
    public static void main(String[] args) {
        String s = new Son().toString();
        System.out.println(s);
    }
}

class Father{
    public String name = "nameDemo";
    public static String nickName ="nickNameDemo";
    //代码块
    {
        System.out.println("普通代码块:name: " + name);
        System.out.println("普通代码块:nickName: " + nickName);
        name = "叮当";
        nickName = "小小";
    }
    static {
        System.out.println("静态代码块:nickName: " + nickName);
        nickName = "大大";
    }
    public Father(){
        name = "bailixiang";
        nickName = "wozhi";
        A();
        System.out.println(this);
        System.out.println("father类的构造方法执行完毕");
    }

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

    @Override
    public String toString() {
        return "Father{" +
                "name='" + name + '\'' +
                "nickName='" + nickName + '\'' +
                '}';
    }
}

class Son extends Father{
    public static String nickName = "dd";
    {
        System.out.println("son中的普通代码块");
    }
    static {
        System.out.println("son中的静态代码块: " + nickName);
        nickName = "son_nickName";
    }
    public Son() {
        System.out.println("son的构造方法");
    }

    @Override
    public void A() {
        System.out.println("子类中的A()方法");
    }

    @Override
    public String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                "nickName='" + nickName + '\'' +
                "super.nickName='" + super.nickName + '\'' +
                '}';
    }
}

结果分析

在这里插入图片描述
在类加载阶段,静态属性便已经别加载到方法区当中了,所以初始化一个子类的时候,首先便是执行父类和子类的静态代码块,接着便是父类中的普通构造代码块以及父类的构造方法,然后便是子类的普通构造代码块,最后是子类的构造方法!

注意的地方

  1. 父类构造方法调用了A() 方法,但是代码确实子类的实现,**System.out.println(this);**同理也是子类的实现,这是在继承体系当中需要特别注意的一点,尽量在构造方法当中不调用会被覆盖的方法。
  2. 关于静态属性,子类中的静态属性并不会覆盖掉父类中静态属性的值,他们只是存放在了不同的地方,程序默认调用子类的静态属性,如果需要显示的调用父类的静态属性的值,则必须使用super关键字进行显示的调用。
发布了22 篇原创文章 · 获赞 20 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_38727626/article/details/83178742