1,集合和泛型
在没有给集合制定类型时,一个集合可以加入任何类型的数据,但是规定了类型之后,则只能放同一种类型的数据
2,泛型是jdk1.5的新特性
3,去类型化(泛型基本可以说是通过编译器实现的,在运行阶段类型会被擦除)
ArrayList<String> lista = new ArrayList<String>();
ArrayList<Integer> listb = new ArrayList<Integer>();
if(lista.getClass() == listb.getClass()){
System.out.println(true
);
运行的时候去类型化,编译完的字节码是同一个,里面已经没有泛型信息,
所以,泛型是给编译器看的,如果绕过编译器,直接操作字节码,泛型的作用就消失了,比如下面的例子
在一个ArrayList<Integer>里面不能直接添加一个String,因为这个时候编译器会报错,而如果用反射,则可以实现
[java] view plaincopyprint?
01.ArrayList<String> lista = new ArrayList<String>();
02.lista.add("abc");
03.//下面一句则会出错,被编译器检查出与泛型信息不匹配
04.//lista.add(1);
05.lista.getClass().getMethod("add", Object.class).invoke(lista, 1);
06.System.out.println(lista);
4,关于泛型的转化兼容关系
看下面代码,大致就能理解常见的转化关系
[java] view plaincopyprint?
01. //原始类型可以 和实例化了的泛型类型相互赋值
02.ArrayList<String> lista = new ArrayList();
03.ArrayList listb = new ArrayList<String>();
04.
05.//参数类型不考虑参数的继承关系,无论是向下转型还是向上转型
06.//ArrayList<String> listc = new ArrayList<Object>();
07.//ArrayList<Object> listd = new ArrayList<String>();
08.//但是,注意,这样则无错
09.ArrayList liste = new ArrayList<String>();
10.ArrayList<Object> listf = liste;
11.
12.//不能创建数组元素为参数类型的数组
13.//ArrayList<String>[] array = new ArrayList<String>[10];
5,问号通配符 ?
作用:问号通配符可以指向各种参数化的引用类型,通配符定义的变量,可以调用与参数化无关的方法(和泛型无关),但是不可以调用和参数化有关的方法
下面是一个输出任何类型集合类的一个方法
[java] view plaincopyprint?
01.public static void PrintAllCollection(Collection<?> collection){
02. //不可以调用和参数化有关的方法,但是可以调用和参数化无关的方法
03. //collection.add(1); //error
04. collection.size();
05.
06. for(Object obj:collection){
07. System.out.println(obj);
08. }
09.
10. //下面一行也是正确的,相当于调用桉树时的转化
11. collection = new ArrayList<String>();
12.}
6,通配符的扩展
限定通配符的上边界
Vector<? extends Number> vec = new Vector<Integer>(); // right
Vector<? extends String> ved = new Vector《Float>(); // error
限定通配符的下边界
Vector<? super Integer> vee = new Vector<Number>(); // right
Vector<? super String> vef = new Vector《Float>(); // error
提示
限定通配符包括自己
关于向上向下转型请看这篇简明扼要的文章 java泛型中的上界下界(上限下限)
下面是关于上界下界的另一个例子
关于?extends
[java] view plaincopyprint?
01. List<Apple> apples = new ArrayList<Apple>();
02.List<? extends Fruit> fruits = apples;
03.//error--fruits.add(new Strawberry());
04.//error--fruits.add(new Apple());
05.//error--fruits.add(new Fruit());
06.Fruit get = fruits.get(0);
07.//原因
08./*
09. * 你可以这样想:这个? extends T 通配符告诉编译器我们在处理一个类型T的子类型,
10. * 但我们不知道这个子类型究竟是什么。因为没法确定,为了保证类型安全,
11. * 我们就不允许往里面加入任何这种类型的数据。另一方面,因为我们知道,不论它是什么类型,
12. * 它总是类型T的子类型,当我们在读取数据时,能确保得到的数据是一个T类型的实例:
13. */
关于? super
[java] view plaincopyprint?
01.List<Fruit> fruits2 = new ArrayList<Fruit>();
02.// error----List<? super Apple> = fruits2;
03.//我们看到fruits指向的是一个装有Apple的某种超类(supertype)的List。
04.//同样的,我们不知道究竟是什么超类,但我们知道Apple和任何Apple的子类都跟它的类型兼容。
05.//既然这个未知的类型即是Apple,也是GreenApple的超类,我们就可以写入:
06.
07.fruits2.add(new Apple());
08.fruits2.add(new GreenApple());
09.//如果我们想往里面加入Apple的超类,编译器就会警告你:
10.
11.//error --- fruits2.add(new Fruit());
12.//error --- fruits2.add(new Object());
13.//因为我们不知道它是怎样的超类,所有这样的实例就不允许加入
|