我在java中进行了关于继承的练习:
public class Gran {
private int x;
public Gran() {
this.x = 68;
}
public int age() {
this.x = this.x+1; return this.x;
}
@Override
public String toString() {
return "Gran " + age();
}
}
public class Dad extends Gran {
private int x;
public Dad(){
this.x = 41;
}
@Override
public String toString() {
return "Dad " + age();
}
}
public class Sis extends Dad {
private int x;
public Sis() {
this.x = 17;
}
@Override
public int age() {
System.out.print("Sis ");
return super.age() - x;
}
@Override
public String toString() {
return "Sis " + super.toString();
}
}
所以当我实施时:
Gran[] family = new Gran[] { new Gran(), new Dad(), new Bro(), new Sis() };
for (Gran member : family) {
System.out.println(member.toString());
}
显示成员Sis : Sis Sis Dad 52
有人可以解释原因吗?
所以这就是我所想的,当调用Sis.toString()
方法时,这意味着:
"Sis" + super.toString()
super.toString() = Dad.toString() = return "Dad" + age()
我很困惑为什么此时age()
方法来自Sis,而不是来自Gran Gran ..
我感谢任何帮助..
答案 0 :(得分:5)
当Dad
' toString()
调用age()
时,应调用的实际方法取决于调用它的对象的运行时类型。由于该对象是Sis
的一个实例,因此调用了age()
Sis
方法,该方法也会调用Gran
' s age()
,因为它包含super.age()
致电return "Sis" + super.toString()
。
所以,我们有:
super.toString()
,其中
"Dad " + age()
返回
age()
但在它返回之前"爸爸52" (69 - 17
返回age()
),Sis Sis Dad 52
打印另一个" Sis"
所以最终输出是
$builder->add('home_team', 'choice', [$options])
->add('away_team', 'choice', [$more_options])
->add('timestamp', 'datetime_picker', [$usual_stuff]);
答案 1 :(得分:1)
你得到了输出:
Sis Sis Dad 52
由于:
1)当您致电new Sis()
时,会调用Sis构造函数,设置x=17
2)然后你调用Sis.toString()
方法。
3)Sis.toString()
来电super.toString()
4)super =爸爸,Dad.toString()
返回:"Dad" + age()
,调用年龄方法。
这是我认为你感到困惑的地方。你期望它可以调用爸爸的年龄方法,因为你是在爸爸的toString()
方法。但是,您使用的实例是Sis
类型。因此,当您致电age()
时,会调用Sis.age()
方法(因为您已经超载了Dad.age()
5)调用Sis.age()
方法,打印“Sis”,然后调用super.age() - x;
。
这是真正丑陋的地方。因为你已经在每个父类和子类中定义了变量x
,你正在经历擦除(不是一个好习惯),其中孩子的x版本会删除父x的可见性和在尝试理解我们引用或修改的x时会产生混淆。
以下是调用Sis.toString()
时age / x会发生什么:
1)在Sis.toString()
中,super.toString()
被调用。
2)super.toString()
= Dad.toString()
。在Dad.toString()
中调用age()
方法。
3)因为我们是Sis
类型,Sis.age()
方法将被执行。
4)Sis.age()
调用super.age()
,然后减去x
的值。
5)在super.age()
上调用Dad
。不用等了! Dad
未覆盖age()
,因此爸爸的父亲 - Gran.age()
被调用。
6)此时在Gran.age()
中,Gran.x
的值为68.在Gran.age()
中,它会增加x的值,使其为69,并返回值。< / p>
7)因此,Gran.age
将值69返回Sis.age()
。 Sis.x
的值仍为17.请记住,Sis和Gran都定义了自己的x
。
8)最后,Sis.age()
方法在减去Gran.age()
(17)= 52的值后返回Sis.x
调用的结果(69)。
不太漂亮。我认为这清楚地突出了擦除的负面影响,并在父类和子类中定义了相同的变量x
- 只是不要这样做。
相反,将Gran中的x
定义为私有,并提供公共或受保护的getX()
(更好地称为'age')方法以授予对子类的访问权限。这样可以避免这种意外行为。