java类初始化和父类子类继承初始化的关系和初始化顺序

首先我们先看下面一段代码

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

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

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

猜想一下上面的主程序运行会输出什么
答案是:(5)(1)(10)(6) (9)(3)(2)(9)(8)(7) (9)(3)(2)(9)(8)(7)

其中考点有:(1)类的初始化过程,(2)方法的重写,(3)实例的初始化过程

(1)类的初始化过程

类在创建实例时就会先加载类本身和初始化本身

而我们的main方法是创建在Son类当中的,而Son类是继承了Father类继承类加载时要先加载父类初始化父类。之后再加载和初始化Son本身。这就是为什么一开始是(5)(1)然后是(10)(6)

而类在加载和初始化时会调用《clinit》方法。clinit方法是由静态类变量显示赋值代码和静态代码块组成。而且调用的顺序是顺序调用。就是谁在上面谁先调用

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

可以发现我们先调用的private static int j = method();再调用了static{}。所以5在1的前面。而且clinit只会在一开始执行一次。

(2)实例的初始化过程

类加载和初始化完成之后就是实例的初始化。实例的初始化实际是就是《init》方法的调用而init方法和clinit方法不同,init方法是可以被调用多次的,具体的次数看构造器的个数

而init方法是由非静态类变量显示赋值代码和非静态代码块以及构造器代码块组成
非静态类变量显示赋值代码和非静态代码块是顺序调用的,但是构造器代码块是一定在最后时候调用

init方法的首行是super()或super(实参)代码,也就是对应父类的实例初始化代码

public class Son extends Father{
	private int i = test();
	private static int j = method();
	static{
		System.out.println("(6)");
	}
	Father(){
	//	super() 写不写这个super()都会存在并且调用
		System.out.println("(7)");
	}
	{
		System.out.println("(8)");
	}
	public int test(){
		System.out.println("(9)");
		return 1;
	}
	public static int method(){
		System.out.println("(10)");
		return 1;
	}

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

(3)方法的重写(override)

非静态方法在创建的时候,也就是init运行的时候。前面会有一个this
这个this表示的是正在创建实例的类,而在main中实际调用的是Son。所以一开始Father调用的private int i = test()调用的是Son类当中的test方法。所以一开始是9,然后是3,2再到Son的非静态和构造器就变成了987

下面来谈一谈什么类型方法不可以重写
(1)final
(2)static
(3)private等子类当中不可见的方法

方法的多态性

(1)子类重写过的方法,调用中方法是通过子类对象调用的都是调用子类过的方法

(2)非静态方法调用时的默认对象是this

(3)this对象在构造器或者说init中就是正在调用的方法

这是方法的重载(overload)和重写(override)的区别

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值