【问题标题】:Instantiating interfaces having default methods [duplicate]实例化具有默认方法的接口
【发布时间】:2017-08-16 03:32:09
【问题描述】:

我遇到了这个问题:

下面的输出是什么?

1  public class A {
2      public static void main(String[] args){
3          I i = new I() {};
4          System.out.println(I.x + i.getValue() + "" + i);
5      }
6  }
7
8  interface I {
9      int x = 10;
10
11     public default int getValue() {
12         return 5;
13     }
14
15     public default String toString() {
16         return "I";
17     }
18 }

我的想法:

我的第一直觉告诉我 - I i = new I() {}?因此,我们无法实例化接口 - 问题 1。

那我想public default String toString()?覆盖对象类方法?听起来不太好 - 问题 2

可能的答案:

a) 10I

b) 15I

c) 由于第 11 行,编译失败

d) 由于第 15 行,编译失败

e) 由于多个错误导致编译失败

在解释了我的想法后,我选择了错误的答案 E)。正确答案是 D),我也答对了。

我的问题 - 为什么以下陈述有效?

I i = new I() {};

由于添加了“{}”,此语句是否在执行我不理解的操作?据我了解,new 关键字的意思是:实例化。

【问题讨论】:

  • 第 11 行和第 15 行分别是什么?
  • 使用编译器编译,自己看结果。
  • 好吧,D 暗示您对问题 2 的看法是正确的。所以您只需要了解 anonymous inner classes

标签: java object interface java-8


【解决方案1】:

声明没有错:

I i = new I() {};

它只是简单地实例化一个实现I 接口的匿名类。由于I 接口只有默认方法,如果不是toString() 方法的问题,空主体就足以实现它。

JLS 9.4.1.2 声明接口不能有toString() 方法的默认实现:

如果默认方法与类 Object 的非私有方法重写等效,则会出现编译时错误,因为任何实现该接口的类都将继承其自己的方法实现.

禁止将 Object 方法之一声明为默认方法可能令人惊讶。毕竟,像 java.util.List 这样的情况下,toString 和 equals 的行为是精确定义的。然而,当理解一些更广泛的设计决策时,动机就会变得更加清晰:

  • 首先,从超类继承的方法可以覆盖从超接口继承的方法(第 8.4.8.1 节)。因此,每个实现类都会自动覆盖接口的 toString 默认值。这是 Java 编程语言中的长期行为。我们不希望通过默认方法的设计来更改它,因为这会与允许接口不显眼地发展的目标相冲突,只有在类还没有通过类层次结构时才提供默认行为。
  • 其次,接口不继承自 Object,而是隐式声明许多与 Object 相同的方法(第 9.2 节)。因此,在 Object 中声明的 toString 和在接口中声明的 toString 没有共同的祖先。充其量,如果两者都是类继承的候选者,它们就会发生冲突。解决这个问题需要将类继承树和接口继承树混为一谈。
  • 第三,在接口中声明对象方法的用例通常假设一个线性接口层次结构;该功能不能很好地推广到多继承场景。
  • 第四,Object 方法是如此基础,以至于允许任意超接口静默添加改变其行为的默认方法似乎很危险。

toString() 是Object 类的方法,因此在任何接口中都不能有默认实现。

【讨论】:

  • I.x 有效吗? x 不是 I 中的静态变量。
  • @marstran: x 是 static 和 final。由于所有接口字段都是public static final,因此您无需明确指定。
  • 感谢一百万伊兰的回复,现在对我来说一切都有意义了。
  • 只是为了强调答案,取自 Brian Goetz 的答案stackoverflow.com/questions/24016962/…“默认值应该是默认值。在没有(层次结构中的任何位置)的接口中添加默认值不应影响具体实现类的语义。但是如果默认值可以“覆盖” Object 方法,那将是不正确的。”
【解决方案2】:

因为加了“{}”我不明白?

你正在实例化匿名类

I i = new I() {};

【讨论】:

    【解决方案3】:

    I i = 新 I() {};创建一个实现接口 I 的匿名类。由于接口 I 没有要实现的任何抽象方法,因此括号 {} 内的匿名类的主体可以为空。

    【讨论】:

      【解决方案4】:

      默认方法不能覆盖来自java.lang.Object 的方法,例如toString()。

      【讨论】:

        猜你喜欢
        • 2017-09-25
        • 2015-01-11
        • 1970-01-01
        • 1970-01-01
        • 2018-01-07
        • 2015-07-31
        • 2020-04-20
        • 2014-12-06
        • 2019-04-02
        相关资源
        最近更新 更多