Я понимаю дженерики, когда дело доходит до коллекций. Но что это значит в случае класса Class<T>
? Когда вы создаете экземпляр объекта Class
, существует только один объект. Итак, почему параметр T
? Что это такое? И почему это необходимо (если это так)?
Что означает общий характер класса Class <T>? Что такое T?
Ответ 1
Параметр <T>
добавлен в java.lang.Class
, чтобы включить один конкретный idiom 1 - использование объектов Class
в качестве объектов объектов, защищенных типом. По существу, добавление <T>
позволяет создавать экземпляры классов безопасным типом, например:
T instance = myClass.newInstance();
Параметр типа <T>
представляет сам класс, позволяющий избежать неприятных эффектов стирания типа, сохраняя Class<T>
в родовом классе или передавая его как параметр в общий метод. Обратите внимание, что T
само по себе не будет достаточным для выполнения этой задачи 2: тип T
стирается, поэтому он становится java.lang.Object
под капотом.
Вот классический пример, когда параметр <T>
класса становится важным. В приведенном ниже примере компилятор Java может обеспечить безопасность типа, позволяя вам создавать типизированную коллекцию из строки SQL и экземпляр Class<T>
. Обратите внимание, что класс используется как factory и что безопасность его типа может быть проверена во время компиляции:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Так как Java стирает параметр типа, делая его java.lang.Object
или класс, указанный в качестве общей верхней границы, важно иметь доступ к объекту Class<T>
внутри метода select
. Поскольку newInstance
возвращает объект типа <T>
, компилятор может выполнять проверку типов, исключая приведение.
<ч/" > 1 SUN Oracle опубликовала хорошую статью, объясняющую все это.
2 Это отличается от реализаций дженериков без стирания типа, например, в .NET.
3Учебник Java Generics от Oracle.
Ответ 2
ответ dasblinkenlight уже продемонстрировал одно из основных применений этого параметра. Есть еще один аспект, который я считаю уместным: используя этот параметр, вы можете ограничить класс, который хотите передать в определенном месте. Так, например,
Class<? extends Number> cls
означает, что cls
может быть любым классом, реализующим интерфейс Number
. Это может помочь поймать определенные ошибки во время компиляции и сделать требования аргументов класса более явными.
Возможно, сравнение с случаем без дженериков в порядке
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
Как вы можете видеть, не имея T
в качестве аргумента, потребуется несколько явных приведений, так как соответствующие методы должны были бы возвращать Object
вместо T
. Если Foo
сам является аргументом общего типа, тогда все эти отбрасывания будут сняты, что приведет к последовательности предупреждений компилятора. Вы можете их подавить, но основная проблема остается: компилятор не может проверить достоверность этих приводов, если вы не используете правильный аргумент типа.
Ответ 3
В Java есть один метакласс: Class
. Его экземпляры (только один для каждого типа существует) используются для представления классов и интерфейсов, поэтому T
in Class<T>
относится к типу класса или интерфейса, который представляет текущий экземпляр Class
.
Ответ 4
Использование дженериков в типе класса top определяет тип класса. Если у меня есть "класс obj", мой объект obj может содержать только детей Charsequence. Это необязательный аргумент. Я часто ставил '?' чтобы избежать предупреждений из Eclipse IDE, если мне не нужен определенный тип класса.