默认方法的协变返回类型

时间:2017-12-14 22:06:26

标签: java default-method covariant-return-types

我可以使用协变返回类型覆盖一个方法,但是是否可以使用协变返回类型覆盖默认方法?在下面的示例中,我想覆盖getFirstLeg而不重写默认方法,但Java不允许这样做。我也不想让Animal成为通用接口,因为可能有很多参数,很多地方都使用Animal。

interface Leg {
}

interface Animal {
    List<? extends Leg> getLegs();

    default Leg getFirstLeg() {
        return getLegs().get(0);
    }
}

abstract class AnimalImpl<T extends Leg> implements Animal {
    private List<T> legs;

    @Override
    public List<T> getLegs() {
        return legs;
    }
}

interface DuckLeg extends Leg {
}

interface Duck extends Animal {
    @Override
    List<? extends DuckLeg> getLegs(); //covariant return type

    @Override
    DuckLeg getFirstLeg(); //I do not want to rewrite this method
}

class DuckImpl extends AnimalImpl<DuckLeg> implements Duck {
    //Error: java: DuckImpl is not abstract and does not override abstract method getFirstLeg() in Duck
}

更新:以下代码编译,但新问题是Duck不再是Animal。

interface Leg {
}

interface AnimalGeneric<T extends Leg> {
    List<? extends T> getLegs();

    default T getFirstLeg() {
        return getLegs().get(0);
    }
}

abstract class AnimalImpl<T extends Leg> implements AnimalGeneric<T> {
    private List<T> legs;

    @Override
    public List<T> getLegs() {
        return legs;
    }
}

interface Animal extends AnimalGeneric<Leg> {
    //empty
}

interface BirdLeg extends Leg {
}

interface BirdGeneric<T extends BirdLeg> extends AnimalGeneric<T> {
}

class BirdImpl<T extends BirdLeg> extends AnimalImpl<T> implements BirdGeneric<T> {
}

interface Bird extends BirdGeneric<BirdLeg> {
    //empty
}

interface DuckLeg extends BirdLeg {
}

class DuckImpl extends BirdImpl<DuckLeg> implements Duck {
}

interface Duck extends BirdGeneric<DuckLeg> {
}

2 个答案:

答案 0 :(得分:0)

是的,Java确实有继承方法的协变返回类型。但问题不在于getFirstLeg是一种default方法,而是Java的泛型不是协变的;他们不变。即List<DuckLeg>不是List<? extends Leg>,即使DuckLegLeg

但是你可以通过使Animal接口通用来解决这个问题,以便type参数可以根据子接口进行更改。

interface Animal<T extends Leg> {
    List<T> getLegs();

    default T getFirstLeg() {
        return getLegs().get(0);
    }
}

然后Duck也有一个类型参数,但不再需要覆盖任何东西。类型参数DuckLeg已分配给T

interface Duck extends Animal<DuckLeg> {
    // able to remove the override of getLegs
    //@Override
    //List<DuckLeg> getLegs(); //covariant return type

    // able to remove the override of getFirstLeg
    //@Override
    //DuckLeg getFirstLeg(); //I do not want to rewrite this method
}

然后你的DuckImpl课将继承正确的一切,你不会得到&#34;不抽象,不会覆盖抽象方法&#34;错误。

当然,对于Duck的空声明,您可能根本不需要它。只需DuckImpl实施Animal<DuckLeg>

class DuckImpl extends AnimalImpl<DuckLeg> implements Animal<DuckLeg> {

}

答案 1 :(得分:0)

如果您想要协方差,请输入Leg。然后,您可以删除大部分代码。

编译:

interface Leg {
}

interface Animal<T extends Leg> {
    List<T> getLegs();

    default T getFirstLeg() {
        return getLegs().get(0);
    }
}

abstract class AnimalImpl<T extends Leg> implements Animal<T> {
    private List<T> legs;

    @Override
    public List<T> getLegs() {
        return legs;
    }
}

interface DuckLeg extends Leg {
}

interface Duck extends Animal<DuckLeg> {
}

class DuckImpl extends AnimalImpl<DuckLeg> implements Duck {
    // no errors
}