访问非重写的超类方法时使用’super’关键字

我试图在Java中获取inheritance权并且已经了解到当在子类中重写方法(和隐藏字段)时,仍然可以使用“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(因此它们脱颖而出)。

不要使用super关键字来引用其他未被覆盖的方法。 这使得其他试图扩展您的类的开发人员感到困惑。

让我们看看一些以这种方式使用super关键字的代码。 这里有2个类: DogCleverDog

 /* 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实现中,使用super关键字调用getName() 。 这意味着它总是调用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 } } 

通过不使用super关键字访问getTyreCost您正在采取正确的方法。

但是您应该将您的成员设置为私有,并且只使用getter方法。

对于需要显式调用父方法的构造函数和重写方法,应使用super关键字。

这取决于您计划如何使用代码。 如果指定super.getTyreCost() ,则稍后覆盖该方法。 您仍将在超类上调用该方法,而不是重写的版本。

在我看来,调用super可能会在以后引起更多的混淆,所以最好只在你明确需要这样做时指定。 但是,对于你在这里提出的案例 – 行为没有区别。

这取决于您的需求和您的愿望。 使用super强制编译/应用程序忽略当前类中的任何潜在方法。 如果您想要通信您只想使用父方法,那么使用super是合适的。 它还将防止将来对您的类进行修改,从而意外地覆盖父方法,从而破坏您的预期逻辑。

但是,这些案件相当罕见。 在课堂上使用超级名称会导致代码混乱,混乱。 在大多数情况下,只需在您自己的类中调用该方法并允许编译器/ jvm确定需要调用哪个方法(超级或本地)更合适。 它还允许您干净地覆盖/修改/操纵超级返回值。

如果你使用super ,你明确告诉使用超类方法(不管子类是否有重写方法),否则首先jvm检查子类中的方法(如果有的话,重写方法),如果不可用则使用超类方法。

重写意味着从具有相同方法签名的子类内的超类重新定义方法。 在你的情况下, getTyreCost()方法没有被覆盖,你还没有重新定义子类中的方法,所以不需要使用super.getTyreCost() ,只有getTyreCost()会这样做(就像super.getTyreCost()一样以同样的方式)。 重写方法时使用super关键字,并且希望在子类中实现的方法调用在超类中实现。

从技术上讲,在这种情况下调用的是inheritance版本,实现实际上是由父类提供的。

可能存在必须使用super关键字的情况。 例如,如果Car已经覆盖了该方法,为了提供自己的不同实现,但是您需要调用父类提供的实现,那么您将使用super关键字。 在这种情况下,您无法省略super关键字,因为如果您这样做,那么您将调用子类本身提供的实现。

建议对inheritance类的进一步更改不需要添加超级​​限定符,并且如果错过则还可以防止错误。