------- android培训、java培训、期待与您交流! ----------
最近学习了Java的泛型编程,在创建集合框架类对象的时候会经常用到,通过指定接收存储元素的数据类型,能够提高对集合框架类操作的安全性。但是,在读代码或者做题过程中经常会碰到参数化的类型与非参数化类型的对象进行引用的题目,以及?通配符及其上下边界限定的问题,搞得很头疼,老是把他们之间的联系弄混,先对这几个问题做一下梳理,也加深一下自己对他们的理解。
1、泛型集合框架中参数化类型和原始类型的兼容性问题。首先,要了解一点就是泛型只在编译时期有效,运行时的时候已经经过了去参数化处理了,所以在运行时阶段可以对集合类添加不同类型的数据信息。即在运行时阶段可以通过反射机制想有参数化类型限制的集合类对象中添加其他类型的数据而不会报错。
如:List<String> list=new ArrayList<String>();那么,若list.add(2);在编译时就会报错,因为添加数据的类型与List指定接收类型不符。但是如果通过反射技术,在运行时添加该数据则不会报错,因在运行时阶段List已经去参数化了。Class cls=list.getClass(); cls.getMethod("add",Object.class).invoke(list,2);即可完成添加整数类型元素的目标。
泛型中,参数化类型可以引用一个原始类型的对象,编译报警告,但可以编译通过——Collection<String> coll=new Vector();编译没问题。
同时原始类型也可以引用一个参数化类型的对象,编译报警告——Collection coll=new Vector<String>();编译通过。
注意,等号两端都指定参数化类型的时候,必须要保证等号两边的参数类型是一致的,否则会报错(参数化类型不考虑参数的继承关系即即使两端的参数类型有继承关系也是不行的),如:
Vector<String> v=new Vector<Object>(); 或者:Vector<Object> v=new Vector<String>();都是编译错误的,因为两端参数化的类型不一致。
思考:Vector v1=new Vector<String>();//编译通过,
Vector<Object> v=v1;//编译通过,因在编译时v1并未指定参数化类型,本条语句相当于将原始类型的容器引用指向带参数化类型的对象,是兼容的。
2、?通配符,通常在对集合框架类对象进行操作的方法中,在不确定访问对象的元素类型的情况下,可以使用?通配符,表示该方法可以接受任意类型的集合对象。如读取操作public void printCollection(Collection<?> collection);注意?通配符的使用规则是它可以引用任意类型的集合对象,但是不能将一个确定类型的集合对象去赋值给一个带?通配符的集合对象,违背了参数化类型兼容性规则。同时在有?通配符的方法中可以通过对象调用与参数化无关的方法,但绝不能调用与参数化相关的方法操作数据,因为在你访问它时是不确定其原始的类型的,故在编译时会报错。
3、关于?通配符的扩展:限定?通配符的上边界和限定?通配符的下边界。
首先是限定通配符的上边界:Vector<? extends Number> x=new Vector<Integer>();编译通过,<>中已经指明该vector可以接收继承自Number的子类对象元素即可以接收如Integer、Double、Long、Byte等基本数据类型的对象。而Vector<? extends Number> x=new Vector<String>();//则会报错,因为String不是Number的子类,两边参数化类型不一致且不兼容,导致编译失败。
第二,限定?通配符的下边界——即只接收某一类型及其父类对象元素。
如:Vector<? super Integer> x=new Vector<Number>();//该段语句编译通过,<>内已经指明,该容器只接收Integer及其父类对象,不接收其他不兼容的参数类型的对象。而语句:Vector<? super Integer> x=new Vector<Byte>();//编译失败,因为两端元素类型不兼容。
4、练习:自定义函数装换Object类对象为其他类型:
public <T> T TransfortObject(Object obj){return (T)obj;}
打印出任意参数化类型的集合对象中的元素:
public void printCollection(Collection<T> col)
{
for(Object obj:col)
System.out.println(obj);
}
或者:
public void printCollection(Collection<?> col)
{
for(Object obj:col)
System.out.println(obj);
}