概述
什么是泛型?为什么要使用泛型
泛型,即“参数化类型”,就是将类型有原来的具体的类型参数化。
参数的本质就是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别称为泛型类、泛型接口、泛型方法。
泛型的使用
1. 泛型类
public class Box<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public static void main(String[] args) {
Box<String> box = new Box<>();
box.setT("123");
System.out.println(box.getT());
}
}
2. 泛型接口
public interface Iterable<T> {
Iterator<T> iterator();
}
3. 泛型方法
public <A> boolean equals(A a1, A a2) {
return a1.equals(a2);
}
边界符
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
通配符
<? extends T>
List<? extends Object> list1 = new ArrayList<Object>();
List<? extends Object> list2 = new ArrayList<String>();
List<? extends Object> list3 = new ArrayList<Integer>();
<? super T>
List<? super Integer> list4 = new ArrayList<Integer>();
List<? super Integer> list5 = new ArrayList<Number>();
List<? super Integer> list6 = new ArrayList<Object>();
List中的通配符
- 对于
<? extends T>
,只能从List里面get元素,不能add元素 - 对于
? super T>
,只能从List里面add元素,不能get元素
Collections类中的copy方法:
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
类型擦除
其实泛型也是Java的一种语法糖
反编译上述Box类,将会得到如下代码,会利用Object类和强转型。
public class Box {
private Object t;
public Object getT() {
return this.t;
}
public void setT(Object t) {
this.t = t;
}
public boolean equals(Object a1, Object a2) {
return a1.equals(a2);
}
public static void main(String[] args) {
Box box = new Box();
box.setT("123");
System.out.println((String)box.getT());
}
}
Class<?> class1 = new ArrayList<String>().getClass();
Class<?> class2 = new ArrayList<Integer>().getClass();
System.out.println(class1 == class2);// true
不允许创建泛型数组
ArrayList<String>[] ls = new ArrayList<String>[10]; // Cannot create a generic array of ArrayList<String>
不能利用类型参数创建实例
public static <E> void append(List<E> list) {
E elem = new E(); // Cannot instantiate the type E
list.add(elem);
}
如果想要类型参数创建实例,可以利用class类
public static <E> void append(List<E> list, Class<E> cls) throws InstantiationException, IllegalAccessException {
E elem = cls.newInstance();
list.add(elem);
}
无法对泛型代码直接使用instanceof关键字
// Cannot perform instanceof check against parameterized type
// ArrayList<Integer>.
// Use the form ArrayList<?> instead since further generic type information will
// be erased at runtime
if (list instanceof ArrayList<Integer>) {
// ...
}
根据提示可以利用list instanceof ArrayList<?>
数组和泛型
Object[] objects = new String[10]; // Ok
List<Object> list = new ArrayList<String>(); // Type mismatch: cannot convert from ArrayList<String> to List<Object>
对于数组右面的声明是数组里包含的内容,可以是Object类或Object的子类
对于泛型右面的声明必须和左边的声明一模一样,除非使用通配符,但是对T赋值的时候,依然可以赋值T的子类,如下:
Box<Object> box = new Box<>();
box.setT("123");