1.泛型的概念:
泛型是Java SE 1.5的新特性,泛型的本质参数化类型,即所操作的数据类型被指定为一个参数。
2.使用泛型的优点:
(1)安全简单,提高代码重用率,在编译的时候检查类型安全,并且所有的强制类型转化都是自动和隐式的;
(2)类型安全,向后兼容,层次清晰,性能较高。
3.元组类库(出处:《Thinking Java》)
(1)定义:元组指将一对对象直接打包存储于其中的一个单一对象,这个容器对象允许读取其中元素,但不允许向其中放入新的对象;
(2)元组可以具有任意长度,元组中的对象可以是任意不同类型。
例:
//一个1维元组,它持有1个对象
class OneTuple<A> {
//code
}
//一个2维元组,它持有两个对象
class TwoTuple<A,B> {
//code
}
4.定义简单泛型
(1)泛型类:具有一个或多个类型变量的类
public class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return this.first;
}
public void setFirst(T newValue) {
this.first = newValue;
}
}
(2)泛型方法:
例:
//普通泛型方法
public class ArrayAlg {
//...表示可变参数
public <T> T getMiddle(T... a) {
return a[a.length/2];
}
}
//集合泛型方法
class ArrayListTest {
public <T> List<T> list() {
return new ArrayList<T>();
}
}
(3)泛型接口
例:
public interface Generator<T> {
T next();
}
(4)泛型应用于匿名内部类
例:
public class Customer {
public Generator<Customer> clerk() {
return new Generator<Customer>() {
@Override
public Customer next() {
return new Customer();
}
};
}
}
5.泛型的擦除
(1)定义;
java字节码中不包含有泛型的类型信息。编译器在编译阶段去掉泛型信息,在运行的时候加上类型信息。
(2)不同类型的擦除
例:
public class ErasedTypeEquairalence{
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}
//输出结果: true
(3)重载中的类型擦除
例:
class HoldItem <T,V>{
public void f(List<T> t) {} // error 编译器报错
public void f(List<V> v) {}
public void f(List<T> t,List<V> v) {}
}
6.泛型的边界
(1)限定类型:< T extends Comparable & Serializable>
由于泛型有擦除行为,所以只能调用Object的toString( ),equals( ),hashCode( )……方法,但若加上限制,
例:< T extends Dog> 就可以使用Dog类中的方法了。
(2)自限定类型: < T extends Access < T >>
若定义一个类F
class F extends Access< u > { }
这个U必须是Access的子类(即:u必须与Access有关)
7.通配符
(1)有限制的通配符
List < ? extends Fruit> 子类型通配符
List < ? super class> 超类型通配符
*生产者消费者模型
助记符:PESC (produce - extends consumer - super)
如果想从列表中读取T类型的元素,则需要将这个列表声明成< ? extends T>,之后就不能往该列表中添加任何元素。
如果想把T类型的元素加入到列表中,则需要把这个列表声明成< ? super T>,之后就不能从中读取元素。
如果一个列表即要生产,又要消费,你不能使用泛型通配符声明列表,比如List < Integer >。
例:
public <T extends Dog> void get1(List<T extends Dog> list){
list.get(0);
}
//error
public <T extends Dog> void set1(List<T extends Dog> list, Dog dog){
list.add(dog);
}
//error
public <T super Cat> void get2(List<T super Cat> list){
list.get(0);
}
public <T super Cat> void set2(List<T super Cat> list, Cat cat){
list.add(cat);
}
例2:Collections类的copy方法就是典型的PECS模型,下面是copy方法的源码
/**
* Copies all of the elements from one list into another. After the
* operation, the index of each copied element in the destination list
* will be identical to its index in the source list. The destination
* list must be at least as long as the source list. If it is longer, the
* remaining elements in the destination list are unaffected. <p>
*
* This method runs in linear time.
*
* @param <T> the class of the objects in the lists
* @param dest The destination list.
* @param src The source list.
* @throws IndexOutOfBoundsException if the destination list is too small
* to contain the entire source List.
* @throws UnsupportedOperationException if the destination list's
* list-iterator does not support the <tt>set</tt> operation.
*/
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());
}
}
}
(2)无界通配符 < ? >
8.约束与局限性
(1)不能用基本数据类型实例化类型参数
(2)运行时类型查询只适用于原始类型
(3)不能创建参数化类型的数组
例:
Pair<String>[] table = new Pair<String> [10]; //error
解决方法:
*使用ArrayList< Pair < String > >
*使用工具类 Arrays.asList()
(4)Varargs警告
抑制警告:@SuppressWarnings(“unchecked”) 或 safe Varargs
(5)不能实例化类型变量
(6)泛型类的静态上下文中类型变量无效
(7)不能抛出或捕获泛型类的实例
(8)防范擦除后的冲突
本人才疏学浅,如有错误,请指出~
谢谢!