泛型,即参数化类型。将类型由运来的具体类型参数化。类似于方法中的变量,定义时为形参,使用或被调用时为实参
分类:泛型类、泛型接口、泛型方法
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//实例化泛型类时,须指定T的具体类型
public class MyClass<T>{
private T key; //key这个成员变量的类型为T,T的类型由外部指定
public MyClass(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
//传入的实参类型需与泛型的类型参数类型相同,即为Integer
//泛型不能指定基本数据类型,如需使用,应指定其封装类
MyClass<Integer> myClass = new MyClass<Integer>(123456);
//泛型支持java的继承属性,此处泛型指定为List,传入的参数为ArrayList
MyClass<List> myClass = new MyClass<List>(new ArrayList<>());
public interface MyInterface<T> {
public T method();
}
//实例化泛型接口时,未指定泛型(用T代替),需将泛型声明加到类中,不加编译报Unknown class错误
class MyClass<T> implements MyInterface<T>{
@Override
public T next() {
return null;
}
}
//指定泛型,所有使用泛型的地方均需替换一致
public class MyClass implements MyInterface<String> {
@Override
public String next() {
return null;
}
}
//public与T之间的可理解为声明此方法为泛型方法,泛型类中使用了泛型的成员方法不是泛型方法
public <T> void method(Class<T> tClass){}
method(tClass);
public <T> void printMsg( T... args){}
由于参数类型的不确定,同种泛型可对应多个版本;不同版本的泛型是不兼容的。
为了使不同版本的泛型实例进行兼容,需要传入其所有版本实例的父类引用类型
//方法中指定需要传入的参数,其类型为Object的子类。
public void method(MyClass<? extends Object> myClass){}
MyClass<Integer> myClass1 = new MyClass<>(new Integer(11));
MyClass<String> myClass2 = new MyClass<>("111");
//由于方法中指定的泛型为Object的子类,所以以上两种泛型实例均可传入method()中
method(myClass1);
method(myClass2);
public void method(Collection> collection){}
public class MyClass<T> {
//静态方法使用泛型必须添加额外的泛型声明,此方法也会变成泛型方法
public static <T> void show(T t){}
}
//传入的类型实参必须是指定类型的子类型
public class MyClass<T extends List>{
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey(){
return key;
}
}
public void method(MyClass<? extends Number> obj){}
public <T extends Number> T showName(Generic<T> container){
...
}
public void method(MyClass<? super ArrayList> myClass){}
//数组的类型不可以是类型变量,除非是采用通配符的方式
List<String>[] lsa = new List<String>[10]; //错误
List<?>[] lsa = new List<?>[10]; //正确
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉
泛型擦除时,泛型类中的类型参数被替换成类型上限。如未指定上限,则被替换成Object。
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
System.out.println(list1.getClass() == list2.getClass()); //true,在jvm中的Class都是List.class
类型擦除会抹掉很多继承相关特性
List<Integer> list = new ArrayList<>();
list.add(123); //正确
list.add("abc"); //错误
List<Integer> ls = new ArrayList<>();
ls.add(23);
try {
Method method = ls.getClass().getDeclaredMethod("add",Object.class);
method.invoke(ls,"test");
method.invoke(ls,42.9f);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}