我们知道的是:“任何一个类的所有实例都共享该类型的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()
现在什么是T? T是类型参数(也称为类型变量);由尖括号(<>)限定,跟随类名。
T只是一个符号,就像在编写类文件时声明的变量名(可以是任何名称)。稍后,在初始化期间,T将被替换为有效的类名(例如:HashMap map = new HashMap())。
例如:
class name
因此,
Class
表示特定类类型'T'的类对象。
假设您的类方法必须使用未知类型参数进行操作,如下所示:
public class Car<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
这里的T可以作为String
类型,如CarName
或者T可以作为Integer
类型,如modelNumber,
或者T可以作为Object
类型,如valid car instance。
现在以上是简单的POJO,它可以在运行时以不同的方式使用。
例如,集合类如List、Set、HashMap就是最好的例子,根据T的声明将与不同的对象一起工作,但是一旦我们将T声明为String,
例如:HashMap<String> map = new HashMap<String>();
那么它只能接受String类实例对象。
泛型方法
泛型方法是引入自己的类型参数的方法。这类似于声明泛型类型,但类型参数的范围限于声明它的方法。允许静态和非静态泛型方法,以及泛型类构造函数。
泛型方法的语法包括一个类型参数,在尖括号内,并出现在方法的返回类型之前。对于泛型方法,类型参数部分必须出现在方法的返回类型之前。
class Util {
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>{
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> {
private T myMethod(T a){
return a;
}
private <T> T myMethod1(Object a){
return (T) a;
}
private T myMethod1(Object a){
return (T) a;
}
private <T> T myMethod2(T a){
return a;
}
private <T> T myMethod3(Class a){
return (T) a;
}
private T myMethod3(Class a){
return (T) a;
}
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
最后,静态方法总是需要显式的
<T>
声明;它不会从类级别的
Class<T>
派生。这是因为类级别的 T 与实例绑定。
另请阅读
限制泛型。
通配符和子类型。
泛型方法的类型参数。