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

hud*_*udi 3 java generics

我有简单的抽象结构

public abstract class Data<A extends Serializable> {

}
Run Code Online (Sandbox Code Playgroud)

然后这个类的String实现

public class StringData extends Data<String> {

}
Run Code Online (Sandbox Code Playgroud)

然后我有接口:

public interface Testicek<A extends Serializable> {

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

}
Run Code Online (Sandbox Code Playgroud)

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

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;
    //}

}
Run Code Online (Sandbox Code Playgroud)

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

And*_*ner 5

public interface Testicek<A extends Serializable> {

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

}
Run Code Online (Sandbox Code Playgroud)

Java允许协变返回类型,这意味着接口的实现可以比父接口返回更具体的类型,因为那些更具体的类型仍然是不那么具体的类型的实例,因此符合接口的约定。

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

里氏替换原则告诉我们,子类必须接受,没有更多的限制参数,并且必须返回没有更多的常规值。

Java不允许您使用“限制较少”的参数类型,因为Java 解析了在编译时要调用的方法的方式(这已经复杂了)。从理论的角度来看,这是不必要的限制,但从实践的角度来看,则更为简单。

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

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

    public abstract D test(D bla);

}
Run Code Online (Sandbox Code Playgroud)

然后,您的实现可以是:

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