Ошибка компилятора о несовместимых отбрасываниях

Извините, если это уже было объяснено, но я не нашел похожих нитей в Интернете.

Сегодня я открыл один класс проекта в среде IDE и увидел ошибку (красная подчеркивание), хотя проект был скомпилирован успешно.

Итак, код:

public interface DatasourceImplementation<T extends Entity> {
     ....
}

public interface Datasource<T extends Entity> {
     ....
}


public interface DsContext {
    @Nullable
    <T extends Datasource> T get(String name);
}

И теперь мы вызываем этот метод следующим образом:

DatasourceImplementation dsImpl = getDsContext().get("dsName");

Idea13 дает мне ошибку (несовместимые типы) - я думаю, что правильно.

В Idea14 здесь нет ошибок.

JDK компилирует его без ошибок - это печально.

Должен сказать, что в нашем проекте класс реализации интерфейса A всегда реализует интерфейс B (возможно, объясняет, почему Idea14 говорит, что это нормально), но, на мой взгляд, это не может оправдать это поведение - потому что обычно я могу создать класс, который реализует A и не реализует B. Я хочу статическую типизацию в моем коде, я не хочу видеть исключения выполнения класса выполнения.

Итак, кто здесь не прав?

Обновление. Добавить скриншот с реальными классами (не уверен, что он объяснит что-то большее, это так же, как я описал)

enter image description here

Ответ 1

JDK верен. Объявление promises, чтобы вернуть ЛЮБОЙ источник данных, если он не соответствует, будет только ошибка времени выполнения. Компилятор может показать некоторые серьезные предупреждения, но должен скомпилировать его. Первоначальный разработчик вашего фрагмента, вероятно, предназначен для того, чтобы избежать явного приведения в каждый вызов.

Различные способы исправления в зависимости от намерения:

  • DataSource<?> get(String name): вызывающему нужно будет DatasourceImplementation.
  • <T extends Datasource> T get(Class<T> dsType, String name). Вызываемая функция может проверять или выбирать возвращаемый тип во время выполнения, например. чтобы вернуть Impl1 или Impl2.
  • <T extends Entity>' Datasource<T> get(String name): Вероятно, это было предназначено. Работает до тех пор, пока DatasourceImplementation не нужно знать конкретный тип сущности. Если это нужно знать, тогда <T extends Entity>' Datasource<T> get(Class<T> entityType, String name) будет лучше.

Ответ 2

на первый взгляд ваш код/​​вопрос кажется немного странным.

У вас есть два интерфейса независимо друг от друга и оба с общим типом.

  • DatasourceImplementation < T extends Entity > и
  • Datasource < T extends Entity >

Однако у вас есть < T extends Entity > не означает, что эти бозе Т равны. На самом деле это могут быть совершенно разные реализации (оба простирающиеся от Entity), где никто не может быть добавлен к другому типу.

Кроме того, у вас есть свой интерфейс

public interface DsContext {
  @Nullable
  <T extends Datasource> T get(String name);
}

где вы говорите, что get-method должен возвращать то, что реализует Datasource. Однако это T полностью независимо от обоих других T. На самом деле компилятор должен жаловаться, что вы используете источник данных как необработанный.

Вы имели в виду <T extends Entity> Datasource<T> get(String name); вместо этого?

Однако, поскольку нет отношения от источника данных к DatasourceImplementation, это два типа, независимо друг от друга, такие же, как у вас есть java.lang.String a java.lang.Number. Попытка присвоить номер объявлению типа String или наоборот также приведет к ошибке компилятора. Следовательно, компилятор, сообщающий об ошибке, кажется совершенно прекрасным.

У фрагментов кода не было ничего важного (наследование)? Кроме того, действительно ли выполнялся компилятор во всех случаях?

Себастьян