今天想着写出一段代码,关于Java类的继承覆盖问题的,运行结果和我想的不一样。
先上代码:
public class 继承覆盖的问题 extends 父类{
public int a=10;
@Override
public void 打印() {
System.out.println("调用了子类方法:"+a);
}
public 继承覆盖的问题(){
//super();//这里有没有反斜杠都一样。
super.打印();
打印();
}
public static void main(String[] args) {
继承覆盖的问题 b=new 继承覆盖的问题();
b.打印();
父类 c=new 父类();
c.打印();
}
}
class 父类{
public int a=20;
public 父类(){
this.打印();
打印();
System.out.println("父类的a="+a);
}
public void 打印() {
System.out.println("调用了父类方法:"+a);
}
}
读者您也不妨推测一下,再在电脑上run一下,看看结果和您预想的是否一致。我估计至少95%的人预计的和实际的结果都不一致。
下面公布一下答案,当然你也可以在自己电脑上运行验证一下,这里注明一下我的jdk版本是1.8_191。
调用了子类方法:0
调用了子类方法:0
父类的a=20
调用了父类方法:20
调用了子类方法:10
调用了子类方法:10
调用了父类方法:20
调用了父类方法:20
父类的a=20
调用了父类方法:20
结果很多人没想到吧?
为什么会是这样的结果,我们可以这样理解:
(几个重要的地方说明一下)
子类为什么会出现a=0的情况,可以这样理解,int a=10这句可以分两步:int a和a=10,类在编译的时候先声明了有哪些变量和方法,是什么类型的,但并没有初始化它们。然后直接从子类跳到了父类那里。运行的流程可以用debug逐步调试来看。
子类构造方法有个//super(),有没有这个“//”结果是一致的,没有这句电脑也会默认在构造方法第一行加上这句。
到父类以后,为什么 this.打印() 和 打印() 两句执行的都是子类的 打印() 方法呢?我们可以这样理解:
我以前以为执行了super()之后是new了一个父类对象,在子类被叫做super,现在看来不是这么简单。
我们知道继承就是子类把父类的非private和final变量和方法复制下来,然后同名的会被覆盖。这里执行了super()以后不光是new了一个父类对象,也把父类的非private和final变量和方法复制到子类来,然后同名的会被覆盖。
所以这里的this是指子类对象, this.打印() 和 打印() 调用的都是子类方法,因为父类的方法被覆盖了。同理,父类的int a=20已经执行过了,为什么打印的时候a=0而非20,因为父类的a被子类的a覆盖了。但是注意了,
System.out.println("父类的a="+a);
这句,a调用的是父类的a(a=20),因为之前是调用的子类方法,子类方法里调用的自然是子类的a,这里在父类对象中调用的a当然是指父类对象的a了。
搞清楚这些问题,后面就轻松了。
super.打印();
调用的还是父类的方法。而
父类 c=new 父类();
c.打印();
两句还是和正常想的一样运行,执行的都是父类里面的东西。