Философия Java3
Шрифт:
// Long r5 = exact2(raw, Ing); // Предупреждения-
// Непроверенное преобразование Holder в Holder<Long>
// Непроверенный вызов метода. exact2(Holder<T>,T)
// применяется к (Holder,Long)
Long гб = exact2(qualified, Ing),
// Long r7 = exact2(unbounded. Ing), // Ошибка-
// exact2(Holder<T>,T) не может применяться к
// (Holder<capture of ?>,Long)
// Long r8 = exact2(bounded, Ing), // Ошибка.
// exact2(Holder<T>,T) не может применяться
// к (Holder<capture of ? extends Long>,Long)
// Long r9 = wildSubtype(raw, Ing); //
// Непроверенное преобразование Holder
// к Holder<? extends Long>
// Непроверенный вызов метода-
// wildSubtype(Holder<? extends T>,T)
// применяется к (Holder.Long)
Long rlO = wildSubtype(qualified. Ing);
// Допустимо, но возвращать может только Object-
Object rll = wildSubtype(unbounded. Ing).
Long rl2 = wildSubtype(bounded. Ing).
// wildSupertype(raw, Ing); // Предупреждения. // Непроверенное преобразование Holder // к Holder<? super Long> // Непроверенный вызов метода: // wildSupertype(Holder<? super T>,T) // применяется к (Holder.Long) wildSupertype(qualified, Ing), // wildSupertype(unbounded, Ing); // Ошибка:
// wildSupertype(Holder<? super T>,T) не может продолжение&
// применяться к (Holder<capture of ?>,Long) // wiIdSupertypeCbounded, Ing); // Ошибка: // wildSupertype(Holder<? super T>,T) не может // применяться к (Holder<capture of ? extends Long>.Long)
}
} ///:-
В методе rawArgs компилятор знает, что Holder является параметризованным типом, поэтому несмотря на то, что здесь он выражен как низкоуровневый тип, компилятору известно, что передача Object методу set небезопасна. Так как в данном случае используется низкоуровневый тип, методу set можно передать объект произвольного типа, и он будет преобразован в Object. Таким образом, при использовании низкоуровневого типа вы лишаетесь проверки на стадии компиляции. Вызов get демонстрирует ту же проблему: никакого Т нет, поэтому результатом может быть только Object.
Может создаться впечатление, что низкоуровневый Holder и Holder<?> — приблизительно одно и то же. Однако метод unboundedArgs демонстрирует различия между ними — в нем выявляются те же проблемы, но информация о них выдается в виде ошибок, а не предупреждений, поскольку низкоуровневый Holder может содержать разнородные комбинации типов, тогда как Holder<?> содержит однородную коллекцию одного конкретного типа.
В exactl и exact2 используются точные параметры типов (то есть без метасимволов). Мы видим, что exact2 обладает иными ограничениями, нежели exactl, из-за дополнительного аргумента.
В wildSubtype ограничения на тип Holder опускаются до Holder с элементами любого типа, удовлетворяющими условию extends Т. И снова это означает, что Т может быть типом Fruit, a holder
Реализация параметризованных интерфейсов
Класс не может реализовать две разновидности одного параметризованного интерфейса — вследствие стирания они будут считаться одним и тем же интерфейсом. Пример конфликта такого рода:
II: generics/MultiplelnterfaceVariants.java
II {CompileTimeError} (He компилируется)
interface Payable<T> {}
class Employee implements Payable<Employee> {}
class Hourly extends Employee
implements Payable<Hourly> {} ///:-
Класс Hourly компилироваться не будет, потому что стирание сокращает Payable<Employee> и Payable<Hourly> до Payable, а в приведенном примере это означало бы двукратную реализацию одного интерфейса. Интересная подробность: если удалить параметризованные аргументы из обоих упоминаний Payable, как это делает компилятор при стирании, программа откомпилируется.
Преобразования типов и предупреждения
Преобразование типа или instanceof с параметром типа не приводит ни к какому эффекту. В следующем контейнере данные хранятся во внутреннем представлении в форме Object и преобразуются к Т при выборке:
//. generics/GenericCast.java
class FixedSizeStack<T> { private int index = 0; private Object[] storage; public FixedSizeStackOnt size) {
storage = new Object[size];
}
public void push(T item) { storage[index++] = item; }
@SuppressWarni ngs("unchecked")
public T popО { return (T)storage[--index], }
}
public class GenericCast {
public static final int SIZE = 10; public static void main(String[] args) { FixedSizeStack<String> strings =
new FixedSizeStack<String>(SIZE); for (String s • "А В С D E F G H I J".splitC' "))
strings.push(s), for(int i = 0. i < SIZE; i++) {
String s = strings pop; System.out.print(s + " ");
} /* Output:
JIHGFEDCBA
*///:-
Без директивы @SuppressWarnings компилятор выдает для рор предупреждение о «непроверенном преобразовании». Вследствие стирания он не знает, безопасно преобразование или нет, поэтому метод рор никакого преобразования не выполняет. Т стирается до первого ограничения, которым по умолчанию является Object, так что рор на самом деле преобразует Object в Object.