问题
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