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

时间:2017-03-23 14:06:03

标签: java object interface 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 }

我的想法:

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

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

可能的答案:

  

a)10I

     

b)15I

     

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

     

d)编译因第15行而失败

     

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

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

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

I i = new I() {};

由于" {}"这句话是否做了我不理解的事情。添加到它?据我所知,new关键字表示:实例化。

4 个答案:

答案 0 :(得分:8)

声明没有错:

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

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

答案 1 :(得分:2)

  

由于添加了“{}”,我不明白?

您正在实例化匿名类

I i = new I() {};

答案 2 :(得分:2)

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

答案 3 :(得分:2)

默认方法无法覆盖java.lang.Object的方法,例如toString()