【问题标题】:Abstract Method Implementation vs Abstract Method Overriding. Do these two mean the same for Abstract Classes?抽象方法实现与抽象方法覆盖。这两个对于抽象类是否意味着相同?
【发布时间】:2017-07-01 01:40:10
【问题描述】:

我即将参加 Java SE 8 程序员 I 考试 (1Z0-808)。我正在使用本学习指南:https://www.selikoff.net/java-oca-8-programmer-i-study-guide/。在回答第 5 章(班级设计)中的复习问题时,我在这个问题上失败了:

以下关于具体子类的说法正确的是? (选择所有适用项)

  1. 具体的子类可以声明为抽象。
  2. 一个具体的子类必须实现所有继承的抽象方法。
  3. 一个具体的子类必须实现定义在一个 继承接口。
  4. 不能将具体的子类标记为 final。
  5. 抽象方法不能被具体子类覆盖。

我的答案是 2 和 5。但只有第 2 个是正确的。我选择了第 5 个答案,因为我认为您确实不能从抽象类中覆盖抽象方法,但是您可以实现它,就像从 Java 8 开始的抽象类一样的接口。

在谈论抽象类时,知道接口抽象方法是实现的,而不是被覆盖的:说“抽象方法可以被具体的子类覆盖”而不是“抽象方法可以被具体的子类实现”是否正确?

如果我们注意第二个答案(这是正确的答案),他们使用了“实施”一词。

【问题讨论】:

  • 1,2,4..........??
  • @SureshAtta 不,哈哈,我已经说过正确的答案是第 5 和第 2。这不是问题
  • 大笑,如果第 5 个是正确答案。
  • @SureshAtta 对不起,我只想说第二个
  • 这个问题的措辞非常糟糕。我可能会找到一个案例,其中每一个句子都是正确的,而另一种案例则每个句子都是错误的。

标签: java inheritance


【解决方案1】:

the specification 是这样使用这个术语的:

如果非abstract 方法m<sub>C</sub> 覆盖类C 的抽象方法m<sub>A</sub>,则称m<sub>C</sub>实现 m<sub>A</sub> 来自C .

在类C 中声明或继承的实例方法m<sub>C</sub>覆盖 C 在接口I 中声明的另一个方法m<sub>I</sub>,如果满足以下所有条件真的:[...]

请注意,它确实使用术语“覆盖” 来表示覆盖接口方法。

用更简单的术语来说,如果一个方法重写了一个抽象方法(来自抽象类或接口),那么重写方法实现抽象方法。不过,它仍被视为覆盖。

abstract class A {
    abstract void m();
    void n() {}
}
class C extends A {
    // C.m() both overrides and implements A.m()
    @Override
    void m() {}
    // C.n() overrides A.n(), but does not implement it
    @Override
    void n() {}
}

【讨论】:

    【解决方案2】:

    Java 语言规范没有定义“具体类”的概念。它确实讨论了具体的方法,其中具体方法具有定义的实现(与没有主体,只有类型签名的抽象方法相反)。 Java 8 的接口中的默认方法在这里有点混乱,但并不完全:即使一个方法有默认实现,它仍然被认为是抽象的(如果没有提供其他实现,默认实现只是简单地复制到实现类中)。

    由于具体类的概念定义不明确,因此很难对它做出任何肯定的陈述。通常,当人们谈论具体类时,他们只是指非抽象类,但我也看到(并且自己使用过)“具体类型”这一表达来指代泛型类型的特定实例。例如,List&lt;T&gt; 是泛型的,但 List&lt;String&gt; 可以被认为是 List&lt;T&gt; 的具体对应物,即使 List 仍然是一个抽象类型(因为它是一个接口)。

    此外,由于一个类可以有多个独立的抽象接口继承层次结构,它可以同时对其中一些是具体的,而对另一些是抽象的!

    简短的回答:当面对自己不了解主题的人设计的测试时,纠结哪个答案是“正确的”变得毫无意义。从规范中学习,因为它是语言中正确内容的规范定义。

    【讨论】:

    • 我搜索了 JLS,发现短语 concrete class 出现in one place, without a definition。 (它在斜体注释中。)“定义不明确”在这里确实是一个准确的描述。
    • “具体”没有一般定义并不重要。问题的上下文是关于单个abstract 方法的简单继承,“具体”的任何常识定义都会产生相同的答案“抽象方法可以被具体子类覆盖”。实际上,您甚至可以使用一个完全无意义的具体定义(例如“精确定义 2 个方法”),它仍然是正确的。我不否认这个问题措辞不好的事实,但只用“问题不好”来回答问题是没有帮助的。当有有效答案时
    • @HTNW:您说:“问题的上下文是关于单个抽象方法的简单继承”。我恭敬地不同意:问题没有这么说。问题的上下文是 Java 语言。您正在简化问题并阅读未给出的上下文。
    【解决方案3】:
    1. 具体的子类可以声明为抽象类。

    由于措辞,这是错误的:concrete calss 不能是 abstract,如果它是子类和抽象, 因此它是一个抽象子类。

    1. 具体的子类必须实现所有继承的抽象方法。

    这实际上是一个trick question。子类必须实现任何抽象方法,但是,如果没有,它也必须声明为抽象类。与问题 1 一样,它是措辞;如果它是抽象,它在技术上不是一个具体子类,所以这个问题是正确的。

    1. 具体的子类必须实现继承接口中定义的所有方法。

    这也是true。但是,如果子类继承自已经实现接口的超类,则子类不必重新实现它们,在这种情况下为 false。

    1. 不能将具体子类标记为 final。

    这是错误的;当然是can

    1. 抽象方法不能被具体子类覆盖。

    这是另一个措辞问题。从技术上讲,您不是overriding 一个抽象方法,而是实现它,所以这是错误的。重写方法意味着您要重写的方法在其父类中具有完全匹配(名称、返回类型、参数)。隐藏方法与覆盖它们相同,只是隐藏仅适用于静态方法和字段。因此,如果一个方法有一个主体,并且您在子类中实现了相同的方法,那么您就是在覆盖它。如果您在子类中实现抽象方法,那么您只是在实现它。如果你在子类中实现了一个静态方法,你就是在隐藏它。

    这些问题的措辞很糟糕,试图传达他们对抽象类、接口和可遗传性的想法。不过,鉴于开发是关于对细节的关注,也许这更重要..

    希望这可以帮助澄清一些事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 2013-09-12
      • 2022-08-18
      • 1970-01-01
      相关资源
      最近更新 更多