概述
泛型(generic type
)指只有在创建对象或者调用方法时才能确定的数据类型。如Constructor<T>
中的T
即为泛型。可以使用泛型的结构有:
①泛型类;
②泛型接口;
③泛型方法;
④泛型形参。
泛型类
泛型类的声明
public class Person<T,K,V> {
public Person(){}
}
注意:
①泛型参数可以不止一个。
②泛型类的类体中,构造器不可带泛型参数,但形参可以由泛型声明。例如:×
:public Person<T,K,V>(T t,K k,V v){}
√
:public Person(T t,K k,V v){}
创建泛型类对象
Person<String,Float,Integer> person = new Person<>();
注意:
①创建泛型类对象调用构造器时要带<>
,但是可以不带泛型参数,编译器根据上下文进行类型推断。
②使用泛型类时可以不带泛型参数列表,如Person person = new Person();
泛型类不带泛型参数列表时称为原类型(raw type
);泛型类带上泛型参数列表时称为参数化类型(parameterized type
)。
③原类型的所有泛型为Object
型。
泛型类的继承
①子类为非泛型类:
public class Man extends Person<String,Float,Integer> {}
此时泛型父类的所有泛型必须明确指定。
②子类为泛型类:
子类继承父类的全部泛型:
public class Man<T,K,V> extends Person<T,K,V> {}
子类可以只继承父类的部分泛型,此时父类未被继承的泛型必须明确指定:
public class Man<K,V> extends Person<String,K,V> {}
子类可以继承父类全部泛型的同时声明新的泛型:
public class Man<T,K,V,E> extends Person<T,K,V> {}
子类可以继承父类部分泛型的同时声明新的泛型:
public class Man<T,K,V> extends Person<String,K,V> {}
注意:
①泛型不可以是基本数据类型,可以使用包装类替换,例如Float
和Integer
等。
②泛型类中的静态结构不可以使用泛型类的泛型。因为泛型类的泛型在实例化对象时指定,而类中静态结构的创建早于类的实例化。例:
public class Person<T> {
public static T t; //Error!
public static void show(){
System.out.println(T); //Error!
}
}
③异常类不可以是泛型类。
④不能直接创建泛型数组,但可以通过强制类型转换间接创建:
×
:T[] t = new T[10];
√
:T[] t = (T[]) new Object[10];
⑤原类型相同而泛型实参不同的泛型类之间不会因为泛型实参的继承关系而具有继承关系,它们是相互并列的类。例如Person<Object>
与Person<String>
不具有继承关系,它们相互并列,因此它们的引用不能相互赋值。
⑥原类型不同而泛型实参相同的泛型类之间会因为原类型的继承关系而具有继承关系。例如Person
类是Man
类的父类,那么Person<String>
也是Man<String>
的父类。
泛型方法
概述
具有泛型结构声明的方法为泛型方法。所谓泛型结构声明是指邻近方法返回类型声明之前的**<泛型列表>**。如:
public <T,K,V> void test() {} //<T,K,V>为泛型结构声明
public <T> List<T> copy(T[] arr) {} //<T>为泛型结构声明
示例
Main.java
/**
*@author Lishaoyin
*@since JDK13
*@version 1.0
*/
public class Main {
public static void main(String[] args) {
String[] strs = {"I'm"+" the"+" best"+"!!!"};
List<String> list = copy(strs);
for(String s : list) {
System.out.print(s);
}
}
/**
*describe: copy from a not sure type array to another
*@param arr T[],generic type array
*@return List<T> generic type array
*/
public static <T> List<T> copy(T[] arr) {
ArrayList<T> list = new ArrayList<>();
for(T t : arr) {
list.add(t);
}
return list;
}
}
注意:
泛型方法可以是静态方法。
通配符的使用
概述
引用泛型类或接口时,可以使用?
代替泛型实参以自动适配不确定的实际场景。编译器会根据上下文确定?
的具体值。例:
Person<?,?,?> person = new Person<String,Float,Integer>();
注意
①泛型通配符只能用于泛型结构的调用,而不能用于泛型结构的声明定义。
②一个泛型通配符只能代替一个泛型参数。例:
×
:Person<?> person = new Person<String,Float,Integer> ();
√
:Person<?,?,?> person = new Person<String,Float,Integer> ();
③可以使用条件限制通配符的适配范围。例:
Man<? extends String> man_1; //实例中的泛型实参必须是String的子类
Man<? super Integer> man_2; //实例中的泛型实参必须是Integer的父类