我正试图在Java中获取继承权并且已经了解到在子类中重写方法(和隐藏字段)时,仍然可以使用“super”关键字从超类中访问它们。
我想知道的是,'super'关键字是否应该用于非重写方法?
是否有任何区别(对于非重写方法/非隐藏字段)?
我在下面举了一个例子。
public class Vehicle {
private int tyreCost;
public Vehicle(int tyreCost) {
this.tyreCost = tyreCost;
}
public int getTyreCost() {
return tyreCost;
}
}
和
public class Car extends Vehicle {
private int wheelCount;
public Vehicle(int tyreCost, int wheelCount) {
super(tyreCost);
this.wheelCount = wheelCount;
}
public int getTotalTyreReplacementCost() {
return getTyreCost() * wheelCount;
}
}
具体而言,鉴于getTyreCost()
尚未被覆盖,getTotalTyreReplacementCost()
应使用getTyreCost()
还是super.getTyreCost()
?
我想知道是否应该在访问超类的字段或方法的所有实例中使用super(在代码中显示您正在访问超类),或者只在被覆盖/隐藏的那些实例中使用super(因此它们代表出)。
答案 0 :(得分:11)
不要使用super
关键字来引用其他未被覆盖的方法。这让其他开发人员试图扩展你的课程感到困惑。
让我们看一下 以这种方式使用super
关键字的代码。这里我们有两个类:Dog
和CleverDog
:
/* file Dog.java */
public static class Dog extends Animal {
private String name;
public Dog(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/* file CleverDog.java */
public class CleverDog extends Dog {
public CleverDog(String name) {
super(name);
}
public void rollover() {
System.out.println(super.getName()+" rolls over!");
}
public void speak() {
System.out.println(super.getName() + " speaks!");
}
}
现在,想象一下你是这个项目的新开发者,你需要为一个聪明的狗在电视上做一些特定的行为:那条狗必须做所有的技巧,但应该用虚构的电视名称。要完成此操作,请覆盖getName(...)
方法...
/* file DogOnTv.java */
public class DogOnTv extends CleverDog {
String fictionalName;
public DogOnTv(String realName, String fictionalName) {
super(realName);
fictionalName = fictionalName;
}
public String getName() {
return fictionalName;
}
}
...并陷入由原始开发者设置的陷阱以及他们对super
关键字的不寻常使用!
上述代码不起作用 - 因为在原始CleverDog
实现中,使用getName()
关键字调用了super
。这意味着它总是调用Dog.getName()
- 与任何重写无关。因此,当您使用新的DogOnTv
类型...
System.out.println("Showcasing the Clever Dog!");
CleverDog showDog = new CleverDog("TugBoat");
showDog.rollover();
showDog.speak();
System.out.println("And now the Dog on TV!");
DogOnTv dogOnTv = new DogOnTv("Pal", "Lassie");
dogOnTv.rollover();
...你得错了输出:
Showcasing the Clever Dog!
Tugboat rolls over!
Tugboat speaks!
And now the Dog on TV!
Pal rolls over!
Pal speaks!
当您覆盖方法时,这不是通常的预期行为,因此您应该避免使用不属于它的super
关键字来创建此类混淆。
但是,如果这实际上是您想要的行为,请使用final
关键字 - 清楚地表明该方法无法覆盖:
/* file CleverDog.java */
public class CleverDog extends Dog {
public CleverDog(String name) {
super(name);
}
public final String getName() { // final so it can't be overridden
return super.getName();
}
public void rollover() {
System.out.println(this.getName()+" rolls over!"); // no `super` keyword
}
public void speak() {
System.out.println(this.getName() + " speaks!"); // no `super` keyword
}
}
答案 1 :(得分:3)
通过不使用super
关键字访问getTyreCost
,您采取了正确的方式。
但是你应该将你的成员设置为私有,只使用getter方法。
对于需要显式调用父方法的构造函数和重写方法,应保留super
关键字。
答案 2 :(得分:2)
这取决于您计划如何使用代码。如果指定super.getTyreCost()
,则稍后覆盖该方法。您仍将在超类上调用该方法,而不是重写版本。
在我看来,调用super可能会在以后引起更多的混淆,所以最好只在明确需要这样做时指定。但是,对于你在这里提出的案例 - 行为没有区别。
答案 3 :(得分:2)
这取决于您的需求和愿望。使用super
强制编译/应用程序忽略当前类中的任何潜在方法。如果您想要通信您只想使用父方法,那么使用super
是合适的。它还可以防止将来对您的类进行修改,从而意外地覆盖父方法,从而破坏您的预期逻辑。
然而,这些案件相当罕见。在你班上的任何地方使用超级将导致非常混乱&杂乱的代码。在大多数一般情况下,只需在您自己的类中调用该方法并允许编译器/ jvm确定需要调用哪个方法(超级或本地)更合适。它还允许您干净地覆盖/修改/操纵超级返回值。
答案 4 :(得分:1)
如果你使用super
,你明确告诉使用超类方法(不管子类是否有重写方法),否则首先jvm检查子类中的方法(如果有的话,重写方法),如果不可用使用超类方法。
答案 5 :(得分:0)
覆盖意味着从具有相同方法签名的子类内的超类重新定义方法。在您的情况下,getTyreCost()
方法尚未被覆盖,您尚未在子类中重新定义该方法,因此无需使用super.getTyreCost()
,只需getTyreCost()
即可(就像{{ 1}}将以同样的方式)。重写方法时使用super.getTyreCost()
关键字,并且希望子类中的方法调用在超类中实现。
答案 6 :(得分:0)
从技术上讲,在这种情况下调用的是继承版本,实现实际上是由父类提供的。
在某些情况下,您必须使用super
关键字。例如如果Car
覆盖了该方法,为了提供自身的不同实现,但是您需要调用父类提供的实现,那么您将使用super
关键字。在这种情况下,您无法忽略super
关键字,因为如果您这样做,那么您将调用子类本身提供的实现。
答案 7 :(得分:-1)
建议对继承类的进一步更改不需要添加超级限定符,并且如果错过则还可以防止错误。