类的执行顺序(静态代码块,子父类等)知识点总结


  • 1. 代码块
  • 1.1 静态代码块
  • 1.2 构造代码块
  • 1.3 构造函数
  • 1.4 代码块的执行顺序
  • 2. 子类和父类
  • 2.1 创建的执行顺序
  • 2.2 子类新建父类的实例
  • 参考材料


1. 代码块

1.1 静态代码块

用static和{}声明的代码块,主要内容写在{}内部。

public class Test {
    static {
        System.out.println("Test类的静态代码块 1");
    }

    static {
        System.out.println("Test类的静态代码块 2");
    }

    public static void main(String[] args) {
    }
}
Test类的静态代码块 1
Test类的静态代码块 2
  • 执行时机:第一次加载这个类的时候(不一定是生成实例,也有可能是调用静态变量或方法)。
  • 一个类中可以有多个静态代码块,按书写顺序执行且都会执行,即写在上面的代码块先执行。
  • 静态代码块有静态特性,不能访问普通变量或方法。

1.2 构造代码块

用{}声明的代码块,主要内容写在{}内部。

public class Test {

    {
        System.out.println("Test类的构造代码块 1");
    }

    {
        System.out.println("Test类的构造代码块 2");
    }

    public static void main(String[] args) {
        new Test(); // 加载一个Test类的实例
    }
}
Test类的构造代码块 1
Test类的构造代码块 2
  • 执行时机:加载一个类的实例的时候。
  • 可以同时有多个构造代码块,按书写顺序执行且都会执行,即写在上面的代码块先执行。
  • 构造代码块在编译生成class文件之后,会把其中所有的代码放到所有的构造方法的上面

1.3 构造函数

常见的构造函数,没有返回类型,方法名就是类名。

public class Test {
    public Test(){
        System.out.println("Test类的构造函数 1");
    }

    public Test(String name){
        System.out.println("Test类的构造函数 2");
    }

    public static void main(String[] args) {
        new Test();
    }
}
Test类的构造函数 1
  • 执行时机:创建对象实例且调用到对应方法时。
  • 可以有多个构造方法,但是参数列表必须不同。

1.4 代码块的执行顺序

执行顺序是:静态代码块 > 构造代码块 > 构造函数。

public class Test {
    static {
        System.out.println("Test类的静态代码块 1");
    }
    
    {
        System.out.println("Test类的构造代码块 1");
    }

    public Test(){
        System.out.println("Test类的构造函数 1");
    }

    public static void main(String[] args) {
    	System.out.println("准备执行new Test()");
        new Test();
    }
}
Test类的静态代码块 1
准备执行new Test()
Test类的构造代码块 1
Test类的构造函数 1

2. 子类和父类

2.1 创建的执行顺序

一律父类先于子类,静态先于动态。无特殊情况(指用super主动调用方法),父类一律是调用无参构造函数。

如果要在子类构造函数中调用super()方法,则必须要将其放在第一行,所以父类一定先于子类执行。

public class T {
    public static void main(String[] args) {
        new Son();
    }
}

class Father {
    static {
        System.out.println("父类的静态代码块");
    }

    {
        System.out.println("父类的构造代码块");
    }

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

}

class Son extends Father{
    static {
        System.out.println("子类的静态代码块");
    }

    {
        System.out.println("子类的构造代码块");
    }

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

    }
}
父类的静态代码块
子类的静态代码块
父类的构造代码块
父类的构造方法
子类的构造代码块
子类的构造方法

2.2 子类新建父类的实例

静态变量和方法一律遵循编译看左边,运行也看左边的原则。

非静态变量和方法一律遵循编译看左边,运行看右边的原则,

  • 当你编译的时候,能不能通过编译,主要看你左边的类是否是右边的类或者它的继承,是就能通过编译。且编译时父类只能调用
  • 当你运行的时候,无论你编译时左边的是父类还是子类,一律调用右边所创建的实例的对应方法。
public class T {
    public static void main(String[] args) {
        Son son = new Son();
        Father father = new Son();

		//你不能通过实例son来调用变量,只能用类名Son
		System.out.println(Son.str); // 子类的静态变量,    
		System.out.println(Father.str); //父类的静态变量
		
        son.func(); // 子类的方法
        father.func(); // 子类的方法
        //father.func2();  无法通过编译,编译时Father类并没有func2()这个方法
    }
}

class Father {
	public static String str = "父类的静态变量";

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

class Son extends Father{
	public static String str = "子类的静态变量";

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

    public void func2(){
        System.out.println("子类的方法2");
    }
}