泛型
以下java.util.ArrayList
类部分代码:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
}
如果未指定泛型<E>
,那么默认类型就是Object
类型。
ArrayList arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(1.2);
arrayList.add("tom");
arrayList.add('a');
for (Object object : arrayList) {
System.out.println(object);
}
如果指定泛型<E>
为String
类型,那么在编译时所有的<E>
都会替换成String
类型。
public class ArrayList<String> extends AbstractList<String> implements List<String>, RandomAccess, Cloneable, java.io.Serializable {
public boolean add(String e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
}
如果使用add
方法参数不是String
类型,编译时会报错:
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("abc");
arrayList.add("123");
arrayList.add(1); // 编译报错
自定义带有泛型的类
public class GenericClass<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
GenericClass<T>
此处的<T>
是泛型的标识符,相当于是定义,或理解为形参。
同时,定义了一个成员变量t
类型为T
,以及变量t
的Getter/Setter方法。
public class Test {
public static void main(String[] args) {
GenericClass genericClass = new GenericClass();
genericClass.setT("Hello Generic!");
Object t = genericClass.getT();
System.out.println("t = " + t);
}
}
不为泛型<T>
指定类型时,默认是Object,因此,setT(Object o)
是可以接受String类型参数的。
若指定了泛型的类型,那么
public class Test {
public static void main(String[] args) {
GenericClass<Integer> genericClass = new GenericClass<>();
genericClass.setT(100);
Integer t = genericClass.getT();
System.out.println("t = " + t);
}
}
setT(Object o)
只能接受Integer类型
以及子类类型
。
自定义带有泛型的方法
public class GenericClass {
public static <T> T get(T x) {
return x;
}
}
在方法的修饰符后,定义或声明泛型标识符<T>
,使用案例:
String string = GenericClass.get("Hello World");
Integer integer = GenericClass.get(100);
Double doubler = GenericClass.get(256.88);
一旦,参数赋值后,类型就确定了。
自定义带有泛型的接口
public interface GenericInterface<T> {
void method(T t);
}
若实现类不指定泛型类型:
public class GenericImpl implements GenericInterface {
@Override
public void method(Object o) {
// TODO
}
}
method方法里的泛型T被替换成了Object
类型;如果指定了泛型呢?
public class GenericImpl implements GenericInterface<String> {
@Override
public void method(String s) {
}
}
method方法里的泛型T被替换成了String
类型!
泛型通配符
当不知道要使用什么类型接收的时候,可以用泛型通配符<?>
来表示:
public class Test {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
GenericClass.printList(strings);
GenericClass.printList(integers);
}
}
比如,有个静态方法printList
需要接收一个List
类型的对象,要求传入List
类型的参数泛型是String
或者Integer
类型,两者都可以。
那么就可以使用泛型通配符来实现:
public class GenericClass<T> {
public static void printList(List<?> list){
for (Object o : list) {
System.out.println("o = " + o);
}
}
}
如果,需求是传入的参数List<?> list
只能是java.lang.Number
类或子类的类型呢?我们可以限制参数中的泛型:
public class GenericClass<T> {
public static void printList(List<? extends Number> list){
// todo
}
}
上限限定extends Number
泛型类型只能是Number的子类或Number类型。
下限限定super Number
泛型类型只能是Number的父类或Number类型。
泛型通配符总结:常用在参数位置和返回值位置,在不清楚传入的参数类型中的泛型或者返回值类型中的泛型是什么类型时,就可以用泛型通配符<T>
来代替。