实例化具有默认方法的接口

arf*_*dee 0 java interface object java-8

我遇到了这个问题:

以下是什么输出?

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

我的想法:

我的第一直觉告诉我 - 我是新的我(){}?因此我们无法实例化接口 - 问题1.

然后我认为公共默认String toString()?重写Object类方法?问题听起来不错 - 问题2

可能答案:

a)10I

b)15I

c)由于第11行导致编译失败

d)由于第15行导致编译失败

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

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

我的问题 - 为什么以下声明有效?

I i = new I() {};
Run Code Online (Sandbox Code Playgroud)

由于添加了"{}",这句话是否做了我不理解的事情?据我所知,new关键字意味着:实例化.

Era*_*ran 8

声明没有错:

I i = new I() {};
Run Code Online (Sandbox Code Playgroud)

它只是实例化一个实现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方法的用例通常假定为线性接口层次结构; 该功能不能很好地概括为多个继承方案.
  • 第四,Object方法非常基础,允许任意超接口静默添加一个改变其行为的默认方法似乎很危险.

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

  • @marstran:`x`*是*`static`和`final`.由于所有接口字段都是`public static final`,因此您无需明确指定. (5认同)