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

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

Слайсер

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

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

Согласно PECS Можете ли вы попробовать использовать super?

Qingfei Yuan 29.05.2019 20:16
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
558
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На первый взгляд это выглядит так, как будто оно должно компилироваться, потому что 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 приводит к сбою компиляции по той же причине, что и 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();
}

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

Спасибо за объяснение! Я думаю, что смогу заставить код работать без необязательных

Stuart Leyland-Cole 29.05.2019 20:34

В разделе «интересно» под «удалить необязательную часть» я имел в виду возвращаемый тип Map<String, ? extends Serializable> в интерфейсе и Map<String, AttributeValue> в классе, которые будут компилироваться.

rgettman 29.05.2019 20:35

Другие вопросы по теме