类、实例初始化

代码 #

 public class Son extends Father{
	private int i=test();
	private static int j=method();
	static {
		System.out.print("(6)");
	}
	Son(){
		System.out.print("(7)");
	}
	{
		System.out.print("(8)");
	}
	public int test(){
		System.out.print("(9)");
		return 1;
	}

	public static int method(){
		System.out.print("(10)");
		return 1;
	}

	public static void main(String[] args) {
		Son s1=new Son();
		System.out.println();
		Son s2=new Son();
	}


}
 public class Father {
	private int i=test();
	private static int j=method();
	static {
		System.out.print("(1)");
	}
	Father(){
		System.out.print("(2)");
	}
	{
		System.out.print("(3)");
	}

	public int test() {
		System.out.print("(4)");
		return 1;
	}

	public static int method() {
		System.out.print("(5)");
		return 1;
	}
}

输出:

(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
(9)(3)(2)(9)(8)(7)

分析 #

  • 类初始化过程

    • 当实例化了一个对象/或main所在类会导致类初始化
    • 子类初始化前会先初始化父类
    • 类初始化执行的是clinit 方法,编译查看字节码可得知 ly-20241212141837597
    • clinit 由静态类变量显示赋值语句 以及 静态代码块组成(由上到下顺序),且只执行一次
      如下
      ly-20241212141837820
  • 实例初始化过程

    • 执行的是init方法 由非静态实例变量显示赋值语句 以及 非静态代码块 [从上到下顺序] 以及对应构造器代码[最后执行] 组成 其中,子类构造器一定会调用super() [最前面] 1) super() 【最前】 2)i = test() 3)子类的非静态代码块 【2,3按顺序】 4) 子类的无参构造(最后)
      ly-20241212141837995
  • 重写的问题 如上所示,初始化Son对象的时候,会先调用super()方法,即初始化父类,然后会先调用父类的 非静态变量赋值以及非静态代码块,最后才是父类的构造器代码块

    调用父类非静态变量赋值的时候,如果调用了非静态方法,就会涉及到重写问题,比如这里的

    public class Father{
     private int i= test();
    }
    

    这里会调用子类(当前正在初始化的对象)的test()方法,而不是父类的test()

    • 哪些方法不可被重写 final方法、静态方法、父类中的private等修饰使得子类不可见的方法