Spec-Zone .ru
спецификации, руководства, описания, API
След: Изучение Языка Java
Урок: (Обновленные) Обобщения
Раздел: Подстановочные знаки
Подстановочное Получение и Методы Помощника
Домашняя страница > Изучение Языка Java > (Обновленные) обобщения

Подстановочное Получение и Методы Помощника

В некоторых случаях компилятор выводит тип подстановочного знака. Например, список может быть определен как List<?>, но, оценивая выражение, компилятор выводит определенный тип из кода. Этот сценарий известен как подстановочное получение.

По большей части Вы не должны волноваться о подстановочном получении, кроме тех случаев, когда Вы видите сообщение об ошибке, которое содержит фразу "получение".

WildcardError пример производит ошибку получения когда компилирующийся:

import java.util.List;

public class WildcardError {

    void foo(List<?> i) {
        i.set(0, i.get(0));
    }
}

В этом примере компилятор обрабатывает входной параметр i как имение типа Object. Когда метод foo вызывает List.set (интервал, E), компилятор не в состоянии подтвердить тип объекта, который вставляется в список, и ошибка производится. Когда этот тип ошибки происходит, это обычно означает, что компилятор полагает, что Вы присваиваете неправильный тип переменной. Обобщения были добавлены к языку Java по этой причине — чтобы осуществить безопасность типов во время компиляции.

Пример WildcardError генерирует следующую ошибку когда компилирующийся JDK Oracle 7 реализаций javac:

WildcardError.java:6: error: method set in interface List<E> cannot be applied to given types;
    i.set(0, i.get(0));
     ^
  required: int,CAP#1
  found: int,Object
  reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
  where E is a type-variable:
    E extends Object declared in interface List
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error

В этом примере код пытается выполнить безопасную работу, так, как можно работать вокруг ошибки компилятора? Можно фиксировать это при записи частного метода помощника, который получает подстановочный знак. В этом случае можно работать вокруг проблемы, создавая частный метод помощника, fooHelper, как показано в WildcardFixed:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }


    // Helper method created so that the wildcard can be captured
    // through type inference.
    private <T> void fooHelper(List<T> l) {
        l.set(0, l.get(0));
    }

}

Благодаря методу помощника компилятор использует вывод, чтобы решить, что T является CAP#1, переменная получения, в вызове. Пример теперь компилирует успешно.

Условно, методы помощника обычно называют originalMethodNameHelper.

Теперь рассмотрите более сложный пример, WildcardErrorBad:

import java.util.List;

public class WildcardErrorBad {

    void swapFirst(List<? extends Number> l1, List<? extends Number> l2) {
      Number temp = l1.get(0);
      l1.set(0, l2.get(0)); // expected a CAP#1 extends Number,
                            // got a CAP#2 extends Number;
                            // same bound, but different types
      l2.set(0, temp);	    // expected a CAP#1 extends Number,
                            // got a Number
    }
}

В этом примере код делает попытку опасной работы. Например, рассмотрите следующий вызов метода swapFirst:

List<Integer> li = Arrays.asList(1, 2, 3);
List<Double>  ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);

В то время как List<Integer> и List<Double> оба выполняют критерии List<? extends Number>, ясно неправильно взять элемент от списка значений Integer и попытки поместить это в список значений Double.

Компилируя код с JDK Oracle компилятор javac производит следующую ошибку:

WildcardErrorBad.java:7: error: method set in interface List<E> cannot be applied to given types;
      l1.set(0, l2.get(0)); // expected a CAP#1 extends Number,
        ^
  required: int,CAP#1
  found: int,Number
  reason: actual argument Number cannot be converted to CAP#1 by method invocation conversion
  where E is a type-variable:
    E extends Object declared in interface List
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Number from capture of ? extends Number
WildcardErrorBad.java:10: error: method set in interface List<E> cannot be applied to given types;
      l2.set(0, temp);      // expected a CAP#1 extends Number,
        ^
  required: int,CAP#1
  found: int,Number
  reason: actual argument Number cannot be converted to CAP#1 by method invocation conversion
  where E is a type-variable:
    E extends Object declared in interface List
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Number from capture of ? extends Number
WildcardErrorBad.java:15: error: method set in interface List<E> cannot be applied to given types;
        i.set(0, i.get(0));
         ^
  required: int,CAP#1
  found: int,Object
  reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
  where E is a type-variable:
    E extends Object declared in interface List
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
3 errors

Нет никакого метода помощника, чтобы работать вокруг проблемы, потому что код является существенно неправильным.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Подстановочные знаки и Выделение подтипов
Следующая страница: Направляющие линии для Подстановочного Использования