Все, что мы знаем: « Все экземпляры любого класса используют один и тот же объект java.lang.Class этого типа класса ».
например)
Student a = new Student();
Student b = new Student();
Тогда a.getClass() == b.getClass()
верно.
Теперь предположим
Teacher t = new Teacher();
без дженериков ниже возможно.
Class studentClassRef = t.getClass();
Но это не так сейчас ..?
например) public void printStudentClassInfo(Class studentClassRef) {}
можно вызвать сTeacher.class
Этого можно избежать, используя дженерики.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Теперь, что такое T ?? T - параметры типа (также называемые переменными типа); ограниченный угловыми скобками (<>), следует за именем класса.
T - это просто символ, похожий на имя переменной (может быть любым именем), объявленной во время записи файла класса. Позже, что T будет заменено
действительным именем класса во время инициализации ( HashMap<String> map = new HashMap<String>();
)
например) class name<T1, T2, ..., Tn>
Таким образом, Class<T>
представляет объект класса определенного типа класса ' T
'.
Предположим, что ваши методы класса должны работать с неизвестными параметрами типа, как показано ниже
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Здесь T может использоваться как String
тип как CarName
ИЛИ T можно использовать как Integer
тип в качестве modelNumber ,
ИЛИ T можно использовать как Object
тип в качестве действительного экземпляра автомобиля .
Теперь выше приведен простой POJO, который можно использовать по-разному во время выполнения.
Коллекции, например) List, Set, Hashmap - лучшие примеры, которые будут работать с различными объектами согласно объявлению T, но как только мы объявили T как String,
например). HashMap<String> map = new HashMap<String>();
Тогда он будет принимать только объекты экземпляров класса String.
Общие методы
Универсальные методы - это методы, которые вводят свои собственные параметры типа. Это похоже на объявление универсального типа, но область действия параметра типа ограничена методом, в котором он объявлен. Разрешены статические и нестатические обобщенные методы, а также конструкторы обобщенных классов.
Синтаксис для универсального метода включает параметр типа, заключенный в угловые скобки, и отображается перед типом возврата метода. Для универсальных методов раздел параметров типа должен появляться перед типом, возвращаемым методом.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Вот <K, V, Z, Y>
объявление типов, используемых в аргументах метода, которые должны быть перед возвращаемым типом, который находится boolean
здесь.
Ниже; объявление типа <T>
не требуется на уровне метода, так как оно уже объявлено на уровне класса.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Но ниже это неверно, так как параметры типа класса K, V, Z и Y нельзя использовать в статическом контексте (здесь статический метод).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
ДРУГИЕ ДЕЙСТВИТЕЛЬНЫЕ СЦЕНАРИИ
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
И наконец, статический метод всегда нуждается в явном <T>
объявлении; Это не будет происходить от уровня класса Class<T>
. Это потому, что уровень класса T связан с экземпляром.
Также прочитайте Ограничения на Дженерики
Подстановочные знаки и подтипы
введите аргумент для универсального метода
Из документации Java:
[...] Что еще более удивительно, класс Class был обобщен. Литералы классов теперь функционируют как токены типов, предоставляя информацию как во время выполнения, так и во время компиляции. Это включает стиль статических фабрик, примером которого является метод getAnnotation в новом интерфейсе AnnotatedElement:
Это общий метод. Он выводит значение параметра типа T из своего аргумента и возвращает соответствующий экземпляр T, как показано в следующем фрагменте:
До генериков вам пришлось бы привести результат к автору. Также у вас не было бы способа заставить компилятор проверить, что фактический параметр представляет подкласс Annotation. [...]
Ну, мне никогда не приходилось использовать такие вещи. Кто угодно?
источник
Class<? extends X>
обозначение, которое я понял, я могу ограничить его только типами «сервис». За исключением того, что не было общего типа «сервис», поэтому я мог сделать это только сClass<?>
. Увы.Я нашел
class<T>
полезным, когда я создаю поиск в реестре сервисов. Напримеристочник
Как указывают другие ответы, есть много веских причин, почему это
class
было сделано обобщенно. Однако есть много раз, когда у вас нет никакого способа узнать универсальный тип для использованияClass<T>
. В этих случаях вы можете просто игнорировать предупреждения желтого затмения или использоватьClass<?>
... Вот как я это делаю;)источник
@SuppressWarnings("unchecked")
приходит на помощь! (Только будьте осторожны , чтобы всегда применять его как небольшая область , насколько это возможно , как это делает неясные потенциальные проблемы в вашем коде.)Следуя ответу @Kire Haglin, еще один пример универсальных методов можно увидеть в документации по демонтажу JAXB :
Это позволяет
unmarshal
возвращать документ произвольного типа дерева содержимого JAXB.источник
Вы часто хотите использовать подстановочные знаки с
Class
. Например,Class<? extends JComponent>
позволит вам указать, что класс является некоторым подклассомJComponent
. Если вы извлеклиClass
экземпляр изClass.forName
, то вы можете использоватьClass.asSubclass
его, прежде чем пытаться, скажем, создать экземпляр.источник
В Java
<T>
означает родовой класс. Общий класс - это класс, который может работать с любым типом данных или, другими словами, мы можем сказать, что он не зависит от типа данных.Где Т означает тип. Теперь, когда вы создаете экземпляр этого класса Shape, вам нужно будет указать компилятору, для какого типа данных он будет работать.
Пример:
Integer - это тип, а String - также тип.
<T>
специально обозначает универсальный тип. Согласно Java Docs - универсальный тип - это универсальный класс или интерфейс, параметризованный по типам.источник
Просто добавьте другой пример, универсальная версия Class (
Class<T>
) позволяет писать универсальные функции, такие как приведенная ниже.источник
Это сбивает с толку в начале. Но это помогает в следующих ситуациях:
источник
Action a = new Action()
?Action
я интерфейс, этоSomeAction
мы пытаемся получить экземпляр. У нас есть только имяSomeAction
доступно во время выполнения.Просто используйте класс говядины:
источник