为什么我不能覆盖使用类的实现作为参数的方法

时间:2019-06-06 13:10:02

标签: java generics

我有简单的抽象结构

public abstract class Data<A extends Serializable> {

}

然后是此类的String实现

public class StringData extends Data<String> {

}

然后我有界面:

public interface Testicek<A extends Serializable> {

    public abstract Data<A> test(Data<A> bla);

}

现在我要创建实现此接口的类:

public class TesticekImpl implements Testicek<String> {


    // OK
    @Override
    public StringData test(Data<String> bla) {
        return null;
    }

    // compilation error
    //@Override
    //public StringData test(StringData bla) {
    //    return null;
    //}

}

为什么我不能将StringData类用作参数,并且只能在返回类型中使用?返回类型和参数的签名相同。

1 个答案:

答案 0 :(得分:5)

public interface Testicek<A extends Serializable> {

    public abstract Data<A> test(Data<A> bla);

}

Java允许covariant return types,这意味着接口的实现可以返回比父接口更具体的类型,因为那些更具体的类型仍然是不那么具体的类型的实例,因此它们符合界面。

但是,您不能使用更具体的参数类型,因为接口的约定规定它必须接受该类型的任何实例。

Liskov Substitution Principle告诉我们,子类必须接受不再具有限制性的参数,并且必须返回不再具有一般性的值。

由于the way it resolves methods to invoke at compile time(已经很复杂了),Java不允许您使用“限制较少”的参数类型。从理论的角度来看,这是不必要的限制,但从实践的角度来看,则更为简单。

就您接受并返回相同类型而言:在您的接口中声明另一个类型变量:

public interface Testicek<A extends Serializable, D extends Data<A>> {

    public abstract D test(D bla);

}

那么您的实现可以是:

public class TesticekImpl implements Testicek<String, StringData> {
    @Override
    public StringData test(StringData bla) {
        return null;
    }
}