Spec-Zone .ru
спецификации, руководства, описания, API
След: Премия
Урок: Обобщения
Мелкий шрифт
Домашняя страница > Премия > Обобщения

Мелкий шрифт

Универсальный Класс Совместно используется Всеми Его Вызовами

Что следующее кодирует печать фрагмента?

List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());

Вы могли бы испытать желание сказать false, но Вы были бы неправы. Это печатает true, потому что у всех экземпляров универсального class есть то же самое время выполнения class, независимо от их фактических параметров типа.

Действительно, что делает class универсальным, факт, что у него есть то же самое поведение для всех его возможных параметров типа; тот же самый class может быть просмотрен как имеющий много различных типов.

Как последствие, статические переменные и методы class также совместно используются среди всех экземпляров. Именно поэтому это недопустимо, чтобы обратиться к параметрам типа описания типа в статическом методе или инициализаторе, или в объявлении или инициализаторе статической переменной.

Броски и InstanceOf

Другая импликация факта, что универсальный class совместно используется среди всех его экземпляров, то, что обычно не имеет никакого смысла спрашивать экземпляр, если это - экземпляр определенного вызова универсального типа:

Collection cs = new ArrayList<String>();
// Illegal.
if (cs instanceof Collection<String>) { ... }

точно так же бросок такой как

// Unchecked warning,
Collection<String> cstr = (Collection<String>) cs;

дает предупреждение непроверенное, так как это не что-то, что система времени выполнения собирается проверить на Вас.

То же самое верно для переменных типа

// Unchecked warning. 
<T> T badCast(T t, Object o) {
    return (T) o;
}

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

Массивы

Компонентный тип объекта массива, возможно, не переменная типа или параметризованный тип, если это не (неограниченный) подстановочный тип. Можно объявить типы массива, тип элемента которых является переменной типа или параметризованным типом, но не объектами массива.

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

// Not really allowed.
List<String>[] lsa = new List<String>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Unsound, but passes run time store check
oa[1] = li;

// Run-time error: ClassCastException.
String s = lsa[1].get(0);

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

Однако, можно все еще использовать подстановочные массивы. Следующее изменение на предыдущем коде воздерживается от использования и объектов массива и типов массива, тип элемента которых параметризован. В результате мы должны бросить явно, чтобы получить a String из массива.

// OK, array of unbounded wildcard type.
List<?>[] lsa = new List<?>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Correct.
oa[1] = li;
// Run time error, but cast is explicit.
String s = (String) lsa[1].get(0);

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

// Error.
List<String>[] lsa = new List<?>[10];

Точно так же попытка создать массив возражает, чей тип элемента является причинами переменной типа ошибка времени компиляции:

<T> T[] makeArray(T t) {
    return new T[100]; // Error.
}

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

Способ работать вокруг этих видов ограничений состоит в том, чтобы использовать литералы class в качестве маркеров типа времени выполнения, столь же описанных в следующем разделе, Литералы Класса как Маркеры Типа времени выполнения.


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

Предыдущая страница: Взаимодействие с Кодом Наследства
Следующая страница: Литералы Класса как Маркеры Типа времени выполнения