第5章 泛型
第23条:请不要在新代码中使用原生态类型
术语 | 示例 |
参数化的类型 | List<String> |
实际类型参数 | String |
泛型 | List<E> |
形式类型参数 | E |
无限制参数类型 | List<?> |
原生态类型 | List |
有限制类型参数 | <E extends Number> |
递归类型限制 | <T extends Comparable<T>> |
有限制通配符类型 | List<? extends Number> |
泛型方法 | static <E> List<E> asList(E[] a) |
类型令牌 | String.class |
泛型类和接口统称为泛型。原生态类型List与Java平台没有泛型之前的接口类型List完全一样。List<String>是List的子类,而不是List<Object>的子类。
第24条:消除非受检警告
要尽可能地消除每一个非受检警告。如果无法消除警告,同时可以证明引起警告的代码是类型安全的,(只有在这种情况下才)可以用一个@SuppressWarnings(”unchecked“)注解来禁止这条警告。
应该始终在尽可能小的范围中使用SuppressWarnings注解。
import java.util.Arrays;
public class CollectionE {
private int size = 10;
private Object[] elements;
public <T> T[] toArray(T[] a){
if(a.length < size)
return (T[])Arrays.copyOf(elements, size, a.getClass());
System.arraycopy(elements, 0, a, 0, size);
if(a.length > size)
a[size] = null;
return a;
}
public static void main(String[] args) {
}
}
最好不要把注解放在整个方法上,而且应该声明一个局部变量来保存返回值,并注解其声明。
public <T> T[] toArray(T[] a){
if(a.length < size){
@SuppressWarnings("unchecked")
T[] result =
(T[])Arrays.copyOf(elements, size, a.getClass());
return result;
}
System.arraycopy(elements, 0, a, 0, size);
if(a.length > size)
a[size] = null;
return a;
}
每当使用SuppressWarnings("unchecked")注解时,都要添加一条注释,说明为什么这么做是安全的。
第25条:列表优先于数组
数组与泛型相比,有两个不同点。首先,数组是协变的,泛型是不可变的。例如以下代码
Object[] obj = new Long[1];
obj[0]= "I Love U";
以上编译不会出错,运行的时候才出错。
List<Object> o1 = new ArrayList<Long>();
o1.add("I Love U");
以上这么写的时候编译就会出现错误。
泛型与数组的第二大区别是,数组是具体化的,泛型则是通过擦除来实现。禁止创建泛型数组。
第26条:优先考虑泛型(针对类)
以强化Stack为例
import java.util.Arrays;
import java.util.EmptyStackException;
public class Stack<E> {
private E[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
@SuppressWarnings("unchecked")
public Stack(){
elements = (E[])new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(E e){
ensureCapacity();
elements[size++] = e;
}
public E pop(){
if(size == 0)
throw new EmptyStackException();
E result = elements[--size];
elements[size] = null;
return result;
}
private void ensureCapacity(){
if(elements.length == size)
elements = Arrays.copyOf(elements, 2*size + 1);
}
}
只要时间允许,就把现有的类型都泛型化。
第27条:优先考虑泛型方法(针对方法)
静态工具方法尤其适合于泛型化,Collections中的所有”算法“方法都泛型化了。
public static <T> Set<T> union(Set<T> s1, Set<T> s2){
Set<T> result = new HashSet<T>(s1);
result.addAll(s2);
return result;
}
public static void main(String[] args) {
Set<String> set1 = new HashSet<String>();
Set<String> set2 = new HashSet<String>();
set1.add("1");
set2.add("2");
set2.add("2");
System.out.println(union(set1, set2));
}
第28条:利用有限制通配符来提升API的灵活性
参数化类型是不可变的。
第29条:优先考虑类型安全的异构容器