Возвращаемый тип в F-ограниченном полиморфизме Java

#java #type-conversion #type-erasure

#java #преобразование типа #стирание типа

Вопрос:

У меня есть интерфейс:

 public interface Message<T extends Message<T>> {
}
  

У меня есть класс, который реализует этот метод как

 public class FulfilmentReleasedDomModel implements Message<FulfilmentReleasedDomModel> {}
  

И у меня есть этот метод:

 private <T extends Message<T>> Mono<T> getDomainModel(ConsumerRecord<String, String> record) {}
  

Когда я пытаюсь вернуть объект типа Mono<FulfilmentReleaseDomModel> из этого метода, компилятор выдает ошибку и просит меня преобразовать его в ( Mono<T> ).

Мой вопрос в том, что, поскольку я ограничил T до extends Message и FulfilmentReleasedDomModel реализует Message<FulfilmentReleasedDomModel> , зачем мне нужно приводить его к Mono<T> ?

Ответ №1:

Распространенное заблуждение относительно дженериков заключается в том, что вызываемый объект решает, каков общий тип. Нет, вызывающий выполняет.

Вы, как автор метода, не можете решать, что T такое. Возвращая Mono<FulfilmentReleasedDomModel> , вы говорите, что это T должно быть FulfilmentReleasedDomModel . Но на самом деле вызывающий ваш метод будет решать, что T такое. Они могли бы объявить тип с именем, Foo который реализует Message<Foo> , и сказать, что это T есть Foo . Вместо этого вам нужно было бы вернуть Mono<Foo> .

Похоже, что ваш метод не должен быть универсальным, потому что вызываемый объект решает, какой тип использовать:

 private Mono<FulfilmentReleasedDomModel> getDomainModel(ConsumerRecord<String, String> record) {}
  

В качестве альтернативы, если вы хотите сделать этот метод более гибким, чтобы вы могли изменить его реализацию, чтобы возвращать что-то другое без изменения возвращаемого типа, вы можете использовать общие подстановочные знаки:

 private Mono<? extends Message> getDomainModel(ConsumerRecord<String, String> record) {}