Java中List<T>和List<?>的区别详解
一、简介
<T>在List、Set、Map中经常见到,用来限制Class中的参数类型,确保Class中参数的一致性。例如:List<String> list = new ArrayList<>();创建了一个内部参数是String类型的类,list中的操作对象都是String。<?>代表任意java类型,只有在不关心数据的具体类型下才使用通配符表示,但在一些情况下,需要将<?>传入的数据进行强转,但这样不如直接传入<T>。
另外除了<?>,还有<? extends T>上界通配符和<? super T>下界通配符。<? extends T> 表示传入数据值需要是T类型或T的子类,<? suprt T>表示传入数据值需要是T类型或T的超类。
一般来说,<?>主要用于变量上,<T>主要用于类或方法上。下图中,list的元素类型为?,但往里边添加String时,会显示出错,因为list中的类型是一个未知的java类型,不属于任何类,所以往里边添加数据时会出错。但可以从list中取出数据,取出的数据类型为Object。
建议采用的顺序是 List<T>、List<?>、List<Object>
二、代码实例
List<?>是只读类型的,不能进行增加、修改操作。
<?>的各种坑
但 List<?>这个写法非常坑。因为,这时候通配符会捕获具体的String类型,但编译器不叫它String,而是起个临时的代号,比如”CAP#1“。所以以后再也不能往list里存任何元素,包括String。唯一能存的就是null。
List<?> list = new ArrayList<String>(); list.add("hello"); //ERROR list.add(111); //ERROR //argument mismatch; String cannot be converted to CAP#1 //argument mismatch; int cannot be converted to CAP#1
另外如果拿List<?>做参数,也会有奇妙的事情发生。还是刚才Box<T>的例子,有get()和set()两个方法,一个存,一个取。
class Box<T>{ private List<T> item; public List<T> get(){return item;} public void set(List<T> t){item=t;} //把item取出来,再放回去 public void getSet(Box<?> box){box.set(box.get());} //ERROR }
新的getSet()方法,只是把item先用get()方法读出来,然后再用set()方法存回去。按理说不可能有问题。实际运行却会报错。
error: incompatible types: Object cannot be converted to CAP#1
原因和前面一样,通配符box<?>.set()的参数类型被编译器捕获,命名为CAP#1,和box<?>.get()返回的Object对象无法匹配。
解决方法,是要给getSet()方法写一个 辅助函数,具体原理可以去查《Java核心技术-卷1》,泛型这章,或者《Java编程思想》。都有讲。
class Box<T>{ private List<T> item; public List<T> get(){return item;} public void set(List<T> t){item=t;} //helper()函数辅助getSet()方法存取元素 public void getSet(Box<?> box){helper(box);} public <V> void helper(Box<V> box){box.set(box.get());} }
到此这篇关于Java中List<T>和List<?>的区别详解的文章就介绍到这了,更多相关List<T>和List<?>内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!