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关键字意味着:实例化.
声明没有错:
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类的方法,因此在任何接口中都不能有默认实现.