1.类型参数
public class Holder<T>
不用特别指定具体类型。
2.返回多个对象
元组:将一组对象存在单一对象。也称为数据传送对象。
public class Tuple<A,B>
3.基本类型无法作为类型参数。
4.泛型方法
原生类型<T>
public <T> void f<T x> 将泛型参数列表置于返回值之前。
public <T> void f<T...x>泛型可变参数,不用显式填充数组x
public static <K,V> Map<K,V> map(){
return new HashMap<K,V>();
}
Map<String,List<String>> sls = New.map();这就是类型参数推断
New.map();//不能编译,不知道类型
New.<String,List<String>>map();//显式类型说明
5.擦除
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
c1==c2//true
Arrays.toString(c1.getTypeParameters())//E
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
6.边界
在编写泛型代码时,都要记住它只是一个Object,严格来说是是它的第一边界。
任何在运行时需要知道确切类型信息的操作都将无法工作。
T extends Hasf 那么Hasf就是T的第一边界。
7.通配符
一个数组new Apple[]可以持有Apple及其子类。
List<Fruit> flist = new ArrayList<Fruit>();//不能写成new ArrayList<Apple>(),
Apple的List不是Fruit的List,Apple的List可以持有Apple及其子类型,Fruit的list则可以持有任何类型的Fruit。
List<? extends Fruit> flist = new ArrayList<Apple>();//什么都不能添加,下界不确定。
从编译器的角度考虑,它要持有Fruit或Fruit的某种子类型,但不知道是那种类型,所以就无法安全的向其中添加任何对象。
这里虽然指明为Apple,但是编译器并不知道,添加任何类型都是不安全的。
List<? super Apple> flist ;//可以添加Apple及其子类,其下界就是Apple
List<? super T>可以,<T super Apple>不合法,T是泛型参数,有可能传错。
无界通配符
List<Integer> li = new ArrayList<Integer>;
li.add(new Integer(12));
List<?> lu = li;
lu.add(new Integer(43));//error
对于lu, 编译器不能对List的类型参数做出足够严密的推理。
add方法类型安全,但是lu擦除并不能确定所加对象的类型。
引入类型通配符,可以从中检索元素,但是不能添加元素。修改功能的方法比不修改方法需要更多的类型信息。
lu.clear();可以运行,因为它不依赖类型安全。
8.泛型问题
a.不能保存基本类型
不能创建ArrayList<int>,可以用ArrayList<Integer>但是性能低。
b.一个类不能实现同一个泛型接口的两种变体
如interface Fruit<t>{} 那么
Class A extends Fruit<Apple> implements Fruit<Orange>{};//error
擦除会使两个接口相同。
c.带有泛型参数的转型和instanceof不会有任何效果
d.重载
void f(List<T> v){}
void f(List<W> v){}
擦除使两个方法相同。
9.动态类型安全
容器的ArrayList<Dog> dl = new ArrayList<Dog>();
虽然有类型安全,但还是有可能加入错的数据。
@SupressWarning("nochecked")
public void addCat(List dogl){
dogl.add(new Cat());
}
addCat(dl);//这是可以的。
所以List<Dog> dl2 = Collections.checkList(dl,Dog.class);//加入类型检查
持续更新中。。。。