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

Типы Non-Reifiable

Стирание Типа раздела обсуждает процесс, куда компилятор удаляет информацию, связанную с параметрами типа и параметрами типа. Стиранию типа связали последствия с переменными параметрами (также известный как varargs) методы, у varargs формального параметра которых есть тип non-reifiable. См. Произвольное число раздела Параметров мимоходом информация к Методу или Конструктору для получения дополнительной информации о varargs методах.

Эта страница затрагивает следующие темы:

Типы Non-Reifiable

Тип reifiable является типом, информация о типе которого полностью доступна во времени выполнения. Это включает примитивы, неуниверсальные типы, необработанные типы, и вызовы несвязанных подстановочных знаков.

Типы Non-reifiable являются типами, куда информация была удалена во время компиляции стиранием типа — вызовы универсальных типов, которые не определяются как неограниченные подстановочные знаки. Тип non-reifiable не имеет всю в наличии свою информацию во времени выполнения. Примерами типов non-reifiable является List<String> и List<Number>; JVM не может сказать различие между этими типами во времени выполнения. Как показано в Ограничениях на Обобщения, есть определенные ситуации, где типы non-reifiable не могут использоваться: в выражении instanceof, например, или как элемент в массиве.

Загрязнение "кучи"

Загрязнение "кучи" происходит, когда переменная параметризованного типа обращается к объекту, который не имеет того параметризованного типа. Эта ситуация происходит, если программа, выполняемая некоторая работа, которая дает начало предупреждению непроверенному во время компиляции. Предупреждение непроверенное сгенерировано, если, любой во время компиляции (в рамках правил проверки типа времени компиляции) или во времени выполнения, правильности работы, включающей параметризованный тип (например, бросок или вызов метода), не может быть проверен. Например, загрязнение "кучи" происходит, смешивая необработанные типы и параметризованные типы, или выполняя броски непроверенные.

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

Потенциальные Уязвимости Методов Varargs с Формальными параметрами Non-Reifiable

Универсальные методы, которые включают входные параметры vararg, могут вызвать загрязнение "кучи".

Считайте следующий ArrayBuilder class:

public class ArrayBuilder {

  public static <T> void addToList (List<T> listArg, T... elements)
{
    for (T x : elements) {
      listArg.add(x);
    }
  }

  public static void faultyMethod(List<String>... l) {
    Object[] objectArray = l;     // Valid
    objectArray[0] = Arrays.asList(42);
    String s = l[0].get(0);       // ClassCastException thrown here
  }

}

Следующий пример, HeapPollutionExample использует ArrayBuiler class:

public class HeapPollutionExample {

  public static void main(String[] args) {

    List<String> stringListA = new ArrayList<String>();
    List<String> stringListB = new ArrayList<String>();

    ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine");
    ArrayBuilder.addToList(stringListA, "Ten", "Eleven", "Twelve");
    List<List<String>> listOfStringLists =
      new ArrayList<List<String>>();
    ArrayBuilder.addToList(listOfStringLists,
      stringListA, stringListB);

    ArrayBuilder.faultyMethod(Arrays.asList("Hello!"),
        		      Arrays.asList("World!"));
  }
}

Когда компилирующийся, следующее предупреждение производится определением метода ArrayBuilder.addToList:

warning: [varargs] Possible heap pollution from parameterized vararg type T

Когда компилятор встречается с varargs методом, он преобразовывает varargs формальный параметр в массив. Однако, язык программирования Java не разрешает создание массивов параметризованных типов. В методе ArrayBuilder.addToList, компилятор преобразовывает varargs формальный параметр T... elements к формальному параметру T[] elements, массив. Однако, из-за стирания типа, компилятор преобразовывает varargs формальный параметр в Object[] elements. Следовательно, есть возможность загрязнения "кучи".

Следующий оператор присваивает varargs формальный параметр l к Object массив objectArgs:

Object[] objectArray = l;

Этот оператор может потенциально представить загрязнение "кучи". Значение, которое действительно соответствует параметризованный тип varargs формального параметра l может быть присвоен переменной objectArray, и таким образом может быть присвоен l. Однако, компилятор не генерирует предупреждение непроверенное в этом операторе. Компилятор уже генерировал предупреждение, когда он преобразовывал varargs формальный параметр List<String>... l к формальному параметру List[] l. Этот оператор допустим; переменная l имеет тип List[], который является подтипом Object[].

Следовательно, компилятор не выпускает предупреждение или ошибку, если Вы присваиваете a List объект любого типа к любому компоненту массива objectArray выстройте как показано этим оператором:

objectArray[0] = Arrays.asList(42);

Этот оператор присваивается к первому компоненту массива objectArray массив с a List объект, который содержит один объект типа Integer.

Предположите, что Вы вызываете ArrayBuilder.makeArray со следующим оператором:

ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));

Во времени выполнения JVM бросает a ClassCastException в следующем операторе:

// ClassCastException thrown here
String s = l[0].get(0);

Объект хранится в первом компоненте массива переменной l имеет тип List<Integer>, но этот оператор ожидает объект типа List<String>.

Предотвратите Предупреждения от Методов Varargs с Формальными параметрами Non-Reifiable

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

@SafeVarargs

@SafeVarargs аннотация является задокументированной частью контракта метода; эта аннотация утверждает, что реализация метода не будет ненадлежащим образом обрабатывать varargs формальный параметр.

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

@SuppressWarnings({"unchecked", "varargs"})

Однако, этот подход не подавляет предупреждения, сгенерированные от сайта вызова метода. Если Вы незнакомы с @SuppressWarnings синтаксис, см. Аннотации.


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

Предыдущая страница: Эффекты Стирания Типа и Мостовых методов
Следующая страница: Ограничения на Обобщения