首先请看如下代码
/**
* Father.java
*/
public class Father {
public int age = 40;
public String getDescription(){
return "I'm the father.";
}
@Override
public String toString() {
// 通过Son调用时,这里的两个this分别是谁?访问的方法或域又是谁?
System.out.println(this instanceof Son);
return "[" + this.getDescription() + /*Father.*/this.age + "]";
}
}
/**
* Son.java
*/
public class Son extends Father {
public int age = 20;
@Override
public String getDescription(){
return "I'm the son.";
}
@Override
public String toString() {
return super.toString() +
"[" + this.getDescription() + this.age + "]";
}
public static void main(String[] args) {
System.out.println(new Son());
}
}
运行Son.main
之后得到输出如下
true
[I'm the son.40][I'm the son.20]
Process finished with exit code 0
1.第一个问题
可以看到,在Son.toString()
里调用super.toString()
方法,而super.toString()
中调用的this.getDescription()
居然实际上是Son.getDescription()
!
这个原因可以作如下解释:
super
关键字和this
关键字不同,它并不是一个引用,仅仅指示编译器去调用超类的方法。
所以调用super.toString()
时传递过去的对象引用仍然是Son,即此时super.toString()
中的this是一个Son对象引用[1],自然会优先调用子类的覆盖方法。
[1] instanceof语句为ture也可以说明这一点。
2.第二个问题
那么问题来了,为什么super.toString()
中的this.age
却访问的是Father对象的age域呢?
可以作如下解释:
Son类在继承Father类时,当然也会把域给继承了过去,也就是说Son对象中的数据域有age
和Father.age
。这里的this虽然是Son对象的引用,但使用超类的方法访问的数据域将会是超类的域,即Father.age
。
此说法为个人理解,存疑。事实上,将Father.age改为private也能被Son的对象引用访问到,这和下面的问题如出一辙。
3.新的问题
接下来将Father.getDescription()
方法改为私有的,同时去除Son.getDescription()
的@Override
覆盖注解。(注意:此时已不是覆盖了)
/**
* Father.java
*/
public class Father {
public int age = 40;
private String getDescription(){
return "I'm the father.";
}
@Override
public String toString() {
System.out.println(this instanceof Son);
return "[" + this.getDescription() + /*Father.*/this.age + "]";
}
}
/**
* Son.java
*/
public class Son extends Father {
public int age = 20;
public String getDescription(){
return "I'm the son.";
}
@Override
public String toString() {
return super.toString() +
"[" + this.getDescription() + this.age + "]";
}
public static void main(String[] args) {
System.out.println(new Son());
}
}
运行结果如下:
true
[I'm the father.40][I'm the son.20]
Process finished with exit code 0
观察输出可以看到,此时竟然调用到了Father类的私有方法,我们可以看到这里的this
仍然是Son对象的引用,那就很奇怪了,为什么子类的引用可以访问到超类的私有方法呢?
此问题待解决,有一个帖子也讨论了这个问题,但是并没有给出能说服我的解答。等学了JVM之后看能不能解惑。
另一个存疑,第一个问题里,如果我就是想调用到通过子类调用到被覆盖的Father.getDescription(),该怎么做?(不要说在子类方法里用super.getDescription(),我指的是子类调用父类方法Father.toString(),然后在Father.toString()中调用父类被覆盖的方法Father.getDescription())
要是有高手知道答案欢迎在评论区指教一下