当前位置: 首页 > 面试题库 >

访问不可覆盖的超类方法时使用“ super”关键字

萧玮
2023-03-14
问题内容

我试图摆脱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关键字来引用其他未被覆盖的方法。这会使其他尝试扩展您的类的开发人员感到困惑。

让我们看一些 确实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实现中,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
    }

}


 类似资料:
  • 问题内容: 当我创建自己的Android自定义类时,它就是本机类。然后,当我要重写基方法,我总是叫方法,就像我一直做的,等 我认为就是这样,因为从一开始,Android团队就建议我们始终调用每个方法重写。 但是,在 许多书籍中, 我可以看到比我自己更有经验的开发人员经常忽略调用,而且我真的怀疑他们是因为缺乏知识而这样做。例如,看看这个基本的SAX,其中解析器类中被省略,并且: 如果尝试通过Ecli

  • 问题内容: 说我有一个像这样的课程: 它具有一个带有扩展它的类的层次结构: 然后在其他地方,我有一堂课利用了这些东西: 我是否可以指定A的子类,以便使用更具体的“某物”类覆盖setSomething方法?这就是我想要做的: 目前,我正在A类中执行以下操作: 如果SuperSomething的类型不适合这些类,则B类和C类在checkClass方法中引发异常。 编辑:我已经尝试使用上述确切的方法签名

  • 问题内容: 我有一个大型的检票口组件库,这些检票口组件使用自定义注释或另一个注释进行注释,该注释具有一个参数以允许多个注释。 这是一个示例代码片段: 到目前为止,我使用apt来检查引用的资源是否确实存在。例如 除非在类路径中找到该文件,否则将导致编译失败。这部分效果很好。 现在,我还是DRY的粉丝,我想使用相同的注释在创建对象时将其实际注入到对象中。使用AspectJ,我已经实现了其中的一部分。

  • 问题内容: 在UIViewController中,此代码: 给出错误 我正在使用Xcode 8 beta 4,且iOS部署目标是9.0,并且在 如何将上面的代码转换为Swift 3? 问题答案: 像这样: …还有其余的。 一般模式 现在,许多Cocoa方法都是属性,因此您可以将它们实现为重写计算变量。因此,从种子3(或更早)移动到种子4的模式是: 更改为 删除 更改为 之所以可行,是因为计算的变量

  • 问题内容: 我更新到Xcode 8 beta 5,现在在从UIView继承的类上收到以下错误: 有解决方法吗? 问题答案: 请检查最新参考。(您只需在Apple开发者网站的搜索栏中输入“ intrinsicContentSize”,就可以轻松找到它。) 宣言 已成为计算属性,因此您需要以这种方式覆盖它: 或者简单地:

  • 我有一个抽象类,割草机,它覆盖了toString()方法。草坪拖拉机类扩展了割草机。它覆盖了toString()方法,并调用super.toString()作为方法的第一行。然后我有一个商业类,它扩展了劳恩拖拉机并覆盖了toString(),也在第一行调用super.toString()。当实例化一个商业对象(声明为割草机对象)并调用它的toString()时,我希望它打印割草机和草坪拖拉机的两个