两个接口都有同名默认方法时,编译器怎么判?父类和接口冲突时谁赢?如果接口是后来才加的默认方法,已经编译的类会怎样?这篇用十多种写法真实编译,并用分开编译的方式复现二进制兼容问题。
类同时实现 A、B(都有 default hi()),不覆盖
→ types A and B are incompatible;
覆盖并用 A.super.hi() 指定
→ 编译通过;运行:A+B
一个默认、一个抽象(A default,B abstract),不覆盖
→ T is not abstract and does not override abstract method hi() in B
B 继承 A 并覆盖 hi(更具体的接口胜出)
→ 编译通过;运行:B
B 继承 A 并覆盖 hi,T 写成 implements B, A(顺序颠倒)
→ 编译通过;运行:B
B 继承 A 并把 hi 重新声明为抽象
→ T is not abstract and does not override abstract method hi() in B
类优先:父类有 hi(),接口有 default hi()
→ 编译通过;运行:P
父类的 hi() 是 abstract,接口有 default hi()
→ T is not abstract and does not override abstract method hi() in P
父类的 hi() 是 private(接口 default hi() 是否生效)
→ 编译通过;运行:Exception in thread "main" java.lang.IllegalAccessError: class T tried to access private method 'java.lang.String P.hi()' (T and P are in unnamed module of loader 'app') | at T.main(T.java:1)
父类的 hi() 是 package-private 且比接口方法弱
→ hi() in P cannot implement hi() in A
用 B.super.hi() 调用没有直接实现的接口(T 只实现 A)
→ not an enclosing class: B
通过间接接口调用(A.super.hi(),A 是 B 的父接口且 T 只实现 B)
→ not an enclosing class: A
接口不能为 Object 的方法提供默认实现(default toString)
→ default method toString in interface A overrides a member of java.lang.Object
静态接口方法不被继承(T.s() 与 A.s())
→ cannot find symbol v1(B 无 hi)运行: A
只替换 B 为新增 default hi() 的 v2,不重新编译 T:
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: A.hi B.hi
at T.hi(T.java)
at T.main(T.java:1)
用 v2 重新编译 T: <实验目录> error: types A and B are incompatible; 1: invokespecial #7 // InterfaceMethod A.hi:()Ljava/lang/String;
5: invokespecial #13 // InterfaceMethod B.hi:()Ljava/lang/String;
8: invokedynamic #16, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
常量池里的接口方法引用: ['A.hi:()Ljava/lang/String;', 'B.hi:()Ljava/lang/String;'] T.getMethod(hi) 声明在:T isDefault=false
U implements B:getMethod(hi) 声明在:B isDefault=true
V implements A, B:声明在:B 调用结果=B
B.class.getMethods() 个数(含继承的接口方法)= 1
B.hi default=true