«Попытка использовать несовместимый тип возвращаемого значения» с классом, реализующим Serializable - PullRequest
1 голос
/ 29 мая 2019

У меня есть следующий интерфейс:

Слайсер

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

из которых у меня есть реализация:

DynamoDbSlicer

public abstract class DynamoDbSlicer implements Slicer {

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

, где AttributeValue взят из AWS SDK и определен как:

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

Обратите внимание, что он реализует Serializable.

Я получаюошибка компилятора в абстрактном методе в DynamoDbSlicer:

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

Что мне не хватает?

1 Ответ

2 голосов
/ 29 мая 2019

На первый взгляд, похоже, что он должен компилироваться, потому что Java (начиная с 1.5) имеет ковариацию возвращаемого типа. Это означает, что переопределяющий метод может объявить возвращаемый тип, который является подтипом возвращаемого типа исходного метода.

Похоже, Optional<Map<String, Serializable>> является подтипом Optional<Map<String, ? extends Serializable>>, но это не так. Интересно, что если вы удалите часть Optional из обоих возвращаемых типов, это скомпилирует.

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

Компилируется, потому что Map<String, Serializable> является подтипом Map<String, ? extends Serializable> - экземпляр первого можно присвоить переменной последнего типа.

Однако добавление Optional делает невозможным компиляцию по той же причине, по которой a List<Dog> не является List<Animal> - генерики являются инвариантными. В этой аналогии Dog подобен определенному подтипу, который соответствует Map<String, Serializable>, а Animal подобен общему типу, который соответствует Map<String, ? extends Serializable>. Также как List<Dog> не List<Animal>, Optional<Map<String, Serializable>> не Optional<Map<String, ? extends Serializable>>.

Самый простой способ получить его для компиляции без удаления бита Optional - это точно соответствовать типу.

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

Если это не соответствует вашим требованиям, вам нужно создать параметр типа на интерфейсе, который ваш класс может предоставить в качестве аргумента типа.

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

Параметр type позволяет это компилировать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...