有一个很好的讨论泛型和他们在这个问题的幕后真正做了什么,所以我们都知道这Vector
是一个整数数组的向量,并且HashTable
是一个表,其键是字符串和值Person
s.然而,困扰我的是使用Class<>
.
java类Class
也应该采用模板名称,(或者我在eclipse中通过黄色下划线告诉我).我不明白我应该放在那里.Class
对象的整个要点是当您没有完全拥有关于对象,反射等的信息时.为什么它让我指定Class
对象将保持哪个类?我显然不知道,或者我不会使用该Class
对象,我会使用具体的一个.
我们所知道的是" 任何类的所有实例都共享该类类型的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
使用泛型可以避免这种情况.
ClassstudentClassRef = t.getClass(); //Compilation error.
现在什么是T ?? T是类型参数(也称为类型变量); 由尖括号(<>)分隔,跟在类名后面.
T只是一个符号,就像在编写类文件时声明的变量名(可以是任何名称).稍后
在初始化期间T将被有效的类名替换(HashMap
)
例如) class name
所以Class
代表一个特定类类型' T
' 的类对象.
假设您的类方法必须使用下面的未知类型参数
/** * Generic version of the Car class. * @paramthe type of the value */ public class Car { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } }
这里T可以String
用作CarName类型
OR T可以用作modelNumberInteger
类型,
OR T可以用作有效汽车实例的Object
类型.
现在,上面是简单的POJO,它可以在运行时以不同的方式使用.
集合例如List,Set,Hashmap是根据T的声明使用不同对象的最佳示例,但是一旦我们将T声明为String,
例如)HashMap
然后它将只接受String Class实例对象.
通用方法
通用方法是引入其自己的类型参数的方法.这类似于声明泛型类型,但类型参数的范围仅限于声明它的方法.允许使用静态和非静态泛型方法,以及泛型类构造函数.
泛型方法的语法包括一个类型参数,在尖括号内,并出现在方法的返回类型之前.对于泛型方法,类型参数部分必须出现在方法的返回类型之前.
class Util { // Generic static method public staticboolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } class Pair { private K key; private V value; }
下面
是方法参数中使用的类型声明,它应该在返回类型之前boolean
.
在下面;
方法级别不需要类型声明,因为它已在类级别声明.
class MyClass{ private T myMethod(T a){ return a; } }
但是下面的错误是因为类级别的参数K,V,Z和Y不能在静态上下文中使用(这里是静态方法).
class Util{ // Generic static method public static boolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } }
其他有效的情景是
class MyClass{ //Type declaration already done at class level private T myMethod(T a){ return a; } // is overriding the T declared at Class level; //So There is no ClassCastException though a is not the type of T declared at MyClass . private T myMethod1(Object a){ return (T) a; } //Runtime ClassCastException will be thrown if a is not the type T (MyClass ). private T myMethod1(Object a){ return (T) a; } // No ClassCastException // MyClass obj= new MyClass (); // obj.myMethod2(Integer.valueOf("1")); // Since type T is redefined at this method level. private T myMethod2(T a){ return a; } // No ClassCastException for the below // MyClass o= new MyClass (); // o.myMethod3(Integer.valueOf("1").getClass()) // Since is undefined within this method; // And MyClass don't have impact here private 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 a :: a is Class object of type T // is overriding of class level type declaration; private Class myMethod4(Class a){ return a; } }
最后静态方法总是需要显式
声明; 它不会来自班级Class
.这是因为类级别T与实例绑定.
另请阅读泛型限制
使用类的类的通用版本允许您(除其他外)编写类似的东西
Class extends Collection> someCollectionClass = someMethod();
然后你可以确定你收到的Class对象扩展了Collection
,这个类的一个实例将是(至少)一个Collection.
从Java文档:
[...]更令人惊讶的是,班级已经普及.类文本现在用作类型标记,提供运行时和编译时类型信息.这样可以在新的AnnotatedElement接口中使用getAnnotation方法示例的静态工厂样式:
T getAnnotation(Class annotationType);
这是一种通用方法.它从参数中推断出其类型参数T的值,并返回一个适当的T实例,如下面的代码片段所示:
Author a = Othello.class.getAnnotation(Author.class);
在泛型之前,您必须将结果转换为Author.此外,您无法让编译器检查实际参数是否表示Annotation的子类.[...]
好吧,我从来没有使用过这种东西.任何人?
我class
在创建服务注册表查找时发现有用.例如
T getService(Class serviceClass) { ... }
正如其他答案所指出的那样,为什么这class
是通用的有很多很好的理由.但是,很多时候您无法知道要使用的泛型类型Class
.在这些情况下,您可以简单地忽略黄色日食警告,或者您可以使用Class>
......这就是我的方式;)