Lui*_*ese 5 java oop overriding interface abstract
我试图理解Java如何处理当具体类从不同的类/接口继承(抽象或具体)具有相同名称的方法时出现的歧义情况.
我无法找到一般规则,这就是为什么我一劳永逸地决定用一种实用的方法来花一些时间.
我考虑了8种不同的情况
导致这个计划:
+-------------------------+
| INTERFACE |
+----------+--------------|
| abstract | non-abstract |
| method | method |
+-----------+--------------+----------+--------------+
| | abstract | | |
| ABSTRACT | method | 1a | 2a |
| +--------------+----------+--------------+
| CLASS | non-abstract | | |
| | method | 3a | 4a |
+-----------+--------------+----------+--------------+
| | abstract | | |
| | method | 1b | 2b |
| INTERFACE +--------------+----------+--------------+
| | non-abstract | | |
| | method | 3b | 4b |
+-----------+--------------+----------+--------------+
Run Code Online (Sandbox Code Playgroud)
在这里,每个案例都得到了实施和评论:
// (1a)
// A - abstract method
// I - abstract method
//
// Implementation needed to avoid compilation error:
// "The type B1 must implement the inherited abstract method A1.foo()"
//
abstract class A1{ abstract void foo(); }
interface I1{ void foo(); }
class B1 extends A1 implements I1{ public void foo(){} }
// (2a)
// A - abstract method
// I - non-abstract method
//
// Implementation needed to avoid compilation error:
// "The type B2 must implement the inherited abstract method A2.foo()"
//
abstract class A2{ abstract void foo(); }
interface I2{ default void foo(){} }
class B2 extends A2 implements I2{ public void foo(){} }
// (3a)
// A - non-abstract method
// I - abstract method
//
// Implementation not needed
//
abstract class A3{ public void foo(){} }
interface I3{ void foo(); }
class B3 extends A3 implements I3{ }
// (4a)
// A - non-abstract method
// I - non-abstract method
//
// Implementation not needed
//
abstract class A4 { public void foo(){System.out.println("A4");}}
interface I4{default void foo(){ System.out.println("I4");} }
class B4 extends A4 implements I4{ B4(){foo();} /*prints "A4"*/ }
// (1b)
// J - abstract method
// K - abstract method
//
// Implementation needed to avoid compilation error:
// "The type C1 must implement the inherited abstract method K1.foo()"
//
interface J1{ void foo(); }
interface K1{ void foo(); }
class C1 implements J1,K1{ public void foo(){} }
// (2b)
// J - abstract method
// K - non-abstract method
//
// Implementation needed to avoid compilation error:
// "The default method foo() inherited from K2 conflicts with another
// method inherited from J2"
//
interface J2{ void foo(); }
interface K2{ default void foo(){} }
class C2 implements J2,K2{ public void foo(){} }
// (3b)
// J - non-abstract method
// K - abstract method
//
// Implementation needed to avoid compilation error:
// "The default method foo() inherited from J3 conflicts with another
// method inherited from K3"
//
interface J3{ default void foo(){} }
interface K3{ void foo(); }
class C3 implements J3,K3{ public void foo(){} }
// (4b)
// J - non-abstract method
// K - non-abstract method
//
// Implementation needed to avoid compilation error:
// "Duplicate default methods named foo with the parameters () and ()
// are inherited from the types K4 and J4"
//
interface J4{ default void foo(){} }
interface K4{ default void foo(){} }
class C4 implements J4,K4{ public void foo(){} }
Run Code Online (Sandbox Code Playgroud)
无论如何,尽管我已经能够理解我的例子中的大部分案例,但我还是无法推断出任何"一般规则".
例如,我不明白为什么案例2a和3a的工作方式不同,即为什么接受抽象类给出的实现,而接口给出的实现不是.
我的最后一个问题是:是否存在任何"一般规则"?有什么方法可以预测编译器的行为,而不必记住每一个案例?
这可能是微不足道的,但我认为对其他人来说,这可能是有用的.
我想你可以通过这个简单的步骤总结所有问题:
给出这样的示例代码
abstract class A{abstract void foo();}
abstract class B extends A {protected void foo(){}}
interface I{void foo();}
interface J{default void foo(){}}
class C extends B implements I,J{}
Run Code Online (Sandbox Code Playgroud)
考虑你的C类由它的所有方法和继承的方法组成(称之为C*)
class C* implements I,J{protected void foo(){};}
针对它实现的接口验证C*(来自接口的每个方法歧义,包括默认方法,必须通过给出实现来解决).
3A.如果C*在此提供有效的实现停止
(it's not the case because method visibility cannot be reduced from public to protected)
3B.否则,C中需要有效的实现
class C extends B implements I,J{public void foo(){}}
JLS 状态 ( \xc2\xa79.4.1.3第 7 段):
\n\n\n\n\n当继承具有匹配签名的抽象方法和默认方法时,我们会产生错误。
\n
然后他们继续解释为什么选择这个:
\n\n\n\n在这种情况下,可以优先考虑其中之一 - 也许我们会假设默认方法也为抽象方法提供了合理的实现。但这是有风险的,因为除了巧合的名称和签名之外,我们没有理由相信默认方法的行为与抽象方法的约定一致——默认方法在子接口最初开发时甚至可能不存在。在这种情况下,要求用户主动断言默认实现是合适的(通过重写声明)会更安全。
\n
归档时间: |
|
查看次数: |
220 次 |
最近记录: |