Подтвердить что ты не робот

Явные шаблоны Java и параметры типа

Почему 1 работа и 2 нет?

1:

public List<? extends Integer> l1;
public List<? extends Number> l2 = l1;

2:

public List<U> l1;
public List<S> l2 = l1;
//where U and S have been previously defined as: **S extends Number,U extends Integer**
4b9b3361

Ответ 1

Дженерики не ковариантны. Например:

List<Integer> l1;
List<Number> l2;
l1 = l2; // incompatible types
l2 = l1; // also incompatible

Однако подстановочные типы предлагают способ выражения ковариации:

List<? extends Integer> l1;
List<? extends Number> l2 = l1; //legal

l1 выражается как List некоторого неизвестного типа, который является или расширяет Integer. Аналогично, l2 является List некоторого типа, который является или продолжается Number. Поскольку Integer extends Number, компилятор знает, что назначение l1 на l2 должно быть в порядке.

Эта ситуация другая:

<S extends Number, U extends Integer> void someMethod() {

    List<U> l1;
    List<S> l2 = l1; //incompatible types
}

S и U являются параметрами типа, что означает, что им предоставляются некоторые конкретные аргументы типа вызывающими абонентами someMethod (или введите inferrence). Эти аргументы типа могут быть конкретным типом типа Integer или подстановочным знаком.

Пока они также ограничены, это отличается от использования ограниченных подстановочных знаков, как указано выше. Параметры типа ограничены при объявлении - внутри тела метода они не могут меняться. Например, допустим, что оба S и U были разрешены к Integer, вызвав:

this.<Integer, Integer>someMethod();

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

List<Integer> l1;
List<Integer> l2 = l1; // okay why not?

Это было бы законно, но нам просто повезло. Есть много ситуаций, когда этого не будет. Например:

this.<Double, Integer>someMethod();

Теперь мы переустановим тело метода:

List<Integer> l1;
List<Double> l2 = l1; // danger!

Итак, вы можете видеть, что параметр ограниченного типа является чем-то большим, чем ограниченный подстановочный знак, который позволяет ковариантно "обмениваться" разными родовыми типами:

List<Integer> l1;
List<Double> l2;
List<? extends Number> l3;
l3 = l1;
l3 = l2;

Ответ 2

BTW: вы не можете расширить Integer, Integer - это класс final.

// l1 holds any subclass of Integer and, because Integer implements Number it is also a subclass of Number
public List<? extends Integer> l1;
// l1 (see above) implements Number so this is fine.
public List<? extends Number> l2 = l1;

// Using Integer here instead of your U because you cannot extend Integer - it is final.
public List<Integer> l3;
// Make S extend Number
static class S extends Number {
  // Implementing the abstract methods of Number
}
// NOT valid because l4 must be a List of S not a list of ANY Number and l3 is a List<Integer> - no connection other than a commmon interface.
public List<S> l4 = l3;

Ответ 3

Look In 1.1 вы говорите любой класс, который расширяет Integer и в 1.2 любой класс, который расширяет Number. Теперь такой способ Integer является подклассом Number, поэтому он не дал никаких ошибок в первом случае. Но это 2.1, вы говорите только U и в 2.2 только S, и вы делаете

 public List<S> l2 = l1

и l1 имеет тип U, а не S, а generics не поддерживают такой объект, ссылающийся на него. Вам нужно будет использовать дикие карты, как в первом случае.

 public List<? extends Number> l2 = l1;

Решает вашу проблему.

Ответ 4

Потому что в 1 вы говорите любой подкласс Integer и Number соответственно.

Но во-вторых, вы говорите, что Generic U и S и, как этот generics, не поддерживают Super могут ссылаться на концепцию объекта класса Sub для java OOP.