Почему компилятор не выводит T (интерфейс) как класс, который реализует T при наличии универсального типа с двойным ограничением?

#java #generics #type-bounds

#java #общие #тип-границы

Вопрос:

У меня есть класс CBound, который реализует два интерфейса IBound1 и Ibound2:

 class CBound implements IBound1, IBound2 {}
 

У меня есть универсальный метод, который принимает в качестве параметра типа тип класса, который реализует как интерфейсы IBound1, так и Ibound2:

  public static <T extends IBound1 amp; IBound2> void getData(T list) {
      //Some code...
}
 

Я создал объект типа IBound1 с внедрением класса CBound:

  IBound1 a = new CBound();
 getData(a); // doesn't work
 

Почему obj a не работает в качестве параметра для getData() ?

Когда я меняю код с помощью :

 CBound b = new CBound();
getData(b); // It works fine
 

Ответ №1:

Компилятор должен вывести a T , который удовлетворяет ограничениям во время компиляции.

Когда вы передаете a , все, что знает компилятор, это то, что a имеет тип IBound1 . Поскольку параметр метода также T равен , у компилятора действительно есть только два варианта T here — IBound1 или Object — nothing , которые удовлетворяют ограничениям.

Вы можете спросить: «Почему компилятор не делает вывод T , что это CBound так?» Ну, в выражении нет ничего getData(a) , что имеет тип CBound . Даже если мы знаем, что a на самом деле это относится к объекту типа CBound , читая предыдущие строки кода, компилятор не учитывает это при выводе T . И даже если T бы предполагалось CBound , что это так, вы не смогли бы перейти a к параметру типа CBound .

В случае b , однако, компилятор очень хорошо знает, что b это тип CBound (потому что вы объявили это так), поэтому он может успешно вывести T , чтобы быть CBound .

Комментарии:

1. Точно так, как сказал @Sweeper. Я бы просто добавил, что когда компилятор статически анализирует ваш код, он не знает a CBound , что это динамический тип объекта, он просто знает статический тип IBound1 . Это сработало бы, если бы вы набрали его. getData((CBound) a)

2. » … вы не сможете передать a параметру типа CBound» — я не понял это хорошо

3. a имеет тип IBound1 (насколько это касается компилятора). Если T бы это было CBound так, тип параметра of getData CBound тоже был бы. Вы не можете передать выражение параметру, если тип этого параметра является подтипом выражения. Например, как вы не можете передать a List принимающему методу ArrayList .