Default interface method for abstract superclass

我们两清 提交于 2019-12-21 09:23:56

问题


Lets say I have the following structure:

abstract class A {
     abstract boolean foo();
}

interface B {
     default boolean foo() { return doBlah(); }
}

class C extends A implements B {
    //function foo
}

Java will now complain that class C must implement abstract method foo from A. I can work around this problem relatively easy by redefining the function in C and simply calling B.super.foo();.

however I do not understand why the default function from interface B does not forfill this requirement on its own, and I would like to have a better understanding of the underlying mechanics of java.


回答1:


At your program's current state, if you were to override A#foo in C.java (where the default method returns true and the overridden method returns false, printing C#foo would result in false, completely ignoring the default method.

Any abstract methods defined in an abstract class are required to be overridden by the first concrete class that extends the abstract class. For this reason, it is required that C.java overrides A#foo.

Default methods within interfaces are not required to be overridden.

However, both methods share identical signatures, meaning that one is required to be overridden and the other may be overridden.

This is extremely poor design and should not be used, as methods that share an identical signature cannot both be overridden. If you want to be required to override the abstract method, then simply change the name of either the abstract method, or the default method to something other than foo.

abstract class A {
    abstract boolean bar();
}

interface B {
    default boolean foo() { return doBlah(); }
}

class C extends A implements B {
    @Override
    public boolean foo() {
        ...
    }   

    @Override
    public boolean bar() {
        ...
    }
}

If you're looking to only override A#foo in some cases, then you can simply remove the abstract method entirely and retain the default method within B.java, and override it in C.java:

abstract class A {

}

interface B {
    default boolean foo() { return doBlah(); }
}

class C extends A implements B {
    @Override
    public boolean foo() {
        ...
    }   
}

If removing A#foo is not an option, then rename the default method, B#foo, to something else.

abstract class A {
    abstract boolean foo();
}

interface B {
    default boolean bar() { return doBlah(); }
}

class C extends A implements B {
    @Override
    public boolean foo() {
        ...
    }   

    @Override
    public boolean bar() {
        ...
    }
}



回答2:


Default methods in Interfaces are used to prevent breaking programs that depend on your Interface when you add a method to your Interface.

In the case you describe, it is unclear if the default method in the interface (which by design must have been added later on) actually fulfills the contract as originally envisioned by the Abstract Class.

In this case it is safer for Java to complain.

Above text is my interpretation of the paragraph in 9.4.1.3 of the JLS SE8 spec, and I quote:

Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).




回答3:


The answer of Jacob G. inspired me to come up with this solution:

interface Z {
     abstract boolean foo();
}

abstract class A implements Z {

}

interface B extends Z {
     default boolean foo() { return doBlah(); }
}

class C extends A implements B {

}

This way all subclasses of class A are required to define a method foo(), Without requiring every class that implements B to re-implement it.



来源:https://stackoverflow.com/questions/43943553/default-interface-method-for-abstract-superclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!