“Attempting to use incompatible return type” with class implementing Serializable

坚强是说给别人听的谎言 提交于 2020-01-05 06:14:48

问题


I have the following interface:

Slicer

public interface Slicer {
    Optional<Map<String, ? extends Serializable>> pointer();
}

of which I have an implementation:

DynamoDbSlicer

public abstract class DynamoDbSlicer implements Slicer {

    @Override
    public abstract Optional<Map<String, AttributeValue> pointer();
}

where AttributeValue is from the AWS SDK and defined as:

public final class AttributeValue implements SdkPojo, Serializable, ToCopyableBuilder<AttributeValue.Builder, AttributeValue> {

Note that it implements Serializable.

I am getting a compiler error on the abstract method in DynamoDbSlicer:

pointer() in DynamoDbSlicer clashes with pointer() in Slicer; attempting to use incompatible return type

What am I missing?


回答1:


At first glance, this looks like it should compile, because Java (since 1.5) has had return type covariance. This means that an overriding method can declare a return type that is a subtype of the original method's return type.

It looks like Optional<Map<String, Serializable>> is a subtype of Optional<Map<String, ? extends Serializable>>, but it's not. Interestingly, if you remove the Optional part from both return types, this compiles.

interface Slicer {
    Map<String, ? extends Serializable> pointer();
}
abstract class DynamoDbSlicer implements Slicer {
    @Override
    public abstract Map<String, Serializable> pointer();
}

It compiles because Map<String, Serializable> is a subtype of Map<String, ? extends Serializable> -- one can assign an instance of the former to a variable of the latter type.

However, adding Optional makes it fail to compile for the same reason that a List<Dog> isn't a List<Animal> -- generics are invariant. In this analogy, Dog is like the specific subtype that matches Map<String, Serializable>, and Animal is like the general type that matches Map<String, ? extends Serializable>. Just like a List<Dog> is not a List<Animal>, a Optional<Map<String, Serializable>> is not a Optional<Map<String, ? extends Serializable>>.

The easiest way of getting this to compile without removing the Optional bit is to match the type exactly.

abstract class DynamoDbSlicer implements Slicer {
    @Override
    public abstract Map<String, ? extends Serializable> pointer();
}

If this doesn't fit your requirements, then you'll need to create a type parameter on the interface that your class can supply as a type argument.

interface Slicer<T extends Serializable> {
    Optional<Map<String, T>> pointer();
}
abstract class DynamoDbSlicer implements Slicer<AttributeValue> {
    @Override
    public abstract Optional<Map<String, AttributeValue>> pointer();
}

The type parameter allows this to compile.



来源:https://stackoverflow.com/questions/56365964/attempting-to-use-incompatible-return-type-with-class-implementing-serializabl

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