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

Jon*_*nny 7 java coding-style super

我试图在Java中获得继承权,并且已经了解到当在子类中重写方法(和隐藏字段)时,仍然可以使用"super"关键字从超类中访问它们.

我想知道的是,'super'关键字是否应该用于非重写方法?

有没有区别(对于非重写方法/非隐藏字段)?

我在下面举了一个例子.

public class Vehicle {
    private int tyreCost;

    public Vehicle(int tyreCost) {
         this.tyreCost = tyreCost;
    }

    public int getTyreCost() {
        return tyreCost;
    }        
}
Run Code Online (Sandbox Code Playgroud)

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;
    }   
}
Run Code Online (Sandbox Code Playgroud)

具体来说,既然getTyreCost()没有被覆盖,应该getTotalTyreReplacementCost()使用getTyreCost(),还是super.getTyreCost()

我想知道是否应该在访问超类的字段或方法的所有实例中使用super(在代码中显示您正在访问超类),或者仅在重写/隐藏的那些实例中使用super(因此它们脱颖而出).

Ric*_*uen 11

不要使用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!");
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,想象一下你是这个项目的新开发者,你需要一些聪明的狗在电视上的特定行为:那条狗必须做所有的技巧,但应该通过它的虚构电视名称.要完成此操作,请覆盖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;
    }

}
Run Code Online (Sandbox Code Playgroud)

...并陷入由原始开发人员设置的陷阱以及他们对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();
Run Code Online (Sandbox Code Playgroud)

...你得到错误的输出:

Showcasing the Clever Dog!
Tugboat rolls over!
Tugboat speaks!

And now the Dog on TV!
Pal rolls over!
Pal speaks!
Run Code Online (Sandbox Code Playgroud)

当您覆盖方法时,这不是通常的预期行为,因此您应该避免使用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
    }

}
Run Code Online (Sandbox Code Playgroud)