我们所知道的是“任何类的所有实例都共享该类的相同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(类studentClassRef){}可以用Teacher.class调用
使用泛型可以避免这种情况。
Class<Student> studentClassRef = t.getClass(); //Compilation error.
那么T是什么?T为类型参数(也称为类型变量);用尖括号(<>)分隔,跟在类名后面。
T只是一个符号,就像写入类文件时声明的变量名(可以是任何名称)一样。稍后,在初始化过程中,T将被有效的类名所取代(HashMap<String> map = new HashMap<String>();)
例)类名<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可以用作字符串类型的CarName
或T可以作为整数类型作为modelNumber,
OR T可以作为对象类型作为有效的汽车实例。
现在上面是一个简单的POJO,可以在运行时使用不同的方法。
例如,集合)List, Set, Hashmap是最好的例子,它们将根据T的声明与不同的对象一起工作,但一旦我们将T声明为字符串
例:HashMap<String> map = new HashMap<String>();然后它将只接受String Class实例对象。
泛型方法
泛型方法是引入自己的类型参数的方法。这类似于声明泛型类型,但类型参数的作用域仅限于声明它的方法。允许使用静态和非静态泛型方法,以及泛型类构造函数。
泛型方法的语法包括一个类型参数,位于尖括号内,出现在方法的返回类型之前。对于泛型方法,类型参数段必须出现在方法的返回类型之前。
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>是方法参数中使用的类型的声明,它应该在返回类型之前,这里是布尔类型。
在下面;类型声明<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;
}
}
最后,Static方法总是需要显式<T>声明;它不会从类级别class <T>派生。这是因为类级别T与实例绑定。
请阅读泛型的限制
通配符和子类型
泛型方法的类型参数