List<T>和List<?>的区别,这问的有点含糊。我想题主是想问类型参数“<T>”和无界通配符“<?>”的区别吧?

讨论“<T>"和"<?>",首先要区分开两种不同的场景:

  1. 第一,声明一个泛型类或泛型方法。
  2. 第二,使用泛型类或泛型方法。

类型参数“<T>”主要用于第一种,声明泛型类或泛型方法。
无界通配符“<?>”主要用于第二种,使用泛型类或泛型方法。

1. <T>声明泛型类的类型参数

List<T>最应该出现的地方,应该是定义一个泛型List容器。但List是库里自带的容器,看看ArrayList的源码头一行:

  1.  
    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.o.Serializable {
  2.  
    ... ...
  3.  
    }

ArrayList<E>中的“E”也是类型参数。只是表示容器中元素Element的时候,习惯用“E”。换一个简单的例子,我们自己定义一个新泛型容器叫Box<T>。

  1.  
    class Box<T>{
  2.  
    private T item1;
  3.  
    private T item2;
  4.  
    }

为什么这里要用类型参数?因为这是一种”约束“,为了保证Box里的item1, item2都是同一个类型T。Box<String>,代表两个item都是String。Box<Integer>里两个item都是Integer。

List容器库里都帮我们写好了,所以我们是不会去定义List<T>的。

那什么时候会出现List<T>?有几种情况,

要么是作为泛型类的成员字段或成员方法的参数间接出现。还是刚才Box<T>的例子,

  1.  
    class Box<T>{
  2.  
    private List<T> item;
  3.  
    public List<T> get(){return item;}
  4.  
    public void set(List<T> t){item=t;}
  5.  
    }

现在Box类里有三个地方出现了List<T>:

  1. 成员字段item的类型
  2. get( )方法的返回值
  3. set( )方法的参数

这里写成List<T>为了表示和Box<T>类型参数保持一致。

2. <T>声明泛型方法

另外一种会出现List<T>的地方是泛型方法。比如Function类的reduce是个静态泛型方法,负责对列表里的所有元素求和。这里的List<T>出现在参数,函数返回值和函数内部,也是为了保持泛型类型的一致性。

  1.  
    class Fuction{
  2.  
    public static <T> List<T> reduce(List<T> list){
  3.  
    //...do something
  4.  
    }
  5.  
    }

3. 无界通配符<?>不能当“类型参数”用

反观List<?>,首先要明确通配符不能拿来声明泛型。像下面这样用通配符"?"来表示类型参数的约束是肯定不行的。

  1.  
    //Error Example
  2.  
    class Box<?>{
  3.  
    private ? item1;
  4.  
    private ? item2;
  5.  
    }

所以通配符是拿来使用定义好的泛型的。比如声明List容器的一个实例对象。

List<?> list = new ArrayList<String>();

4. <?>的各种坑

但List<?>这个写法非常坑。因为,这时候通配符会捕获具体的String类型,但编译器不叫它String,而是起个临时的代号,比如”CAP#1“。所以以后再也不能往list里存任何元素,包括String。唯一能存的就是null。

  1.  
    List<?> list = new ArrayList<String>();
  2.  
     
  3.  
    list.add("hello"); //ERROR
  4.  
    list.add(111); //ERROR
  5.  
     
  6.  
    //argument mismatch; String cannot be converted to CAP#1
  7.  
    //argument mismatch; int cannot be converted to CAP#1

另外如果拿List<?>做参数,也会有奇妙的事情发生。还是刚才Box<T>的例子,有get()和set()两个方法,一个存,一个取。

  1.  
    class Box<T>{
  2.  
    private List<T> item;
  3.  
    public List<T> get(){return item;}
  4.  
    public void set(List<T> t){item=t;}
  5.  
    //把item取出来,再放回去
  6.  
    public void getSet(Box<?> box){box.set(box.get());} //ERROR
  7.  
    }

新的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编程思想》。都有讲。

  1.  
    class Box<T>{
  2.  
    private List<T> item;
  3.  
    public List<T> get(){return item;}
  4.  
    public void set(List<T> t){item=t;}
  5.  
    //helper()函数辅助getSet()方法存取元素
  6.  
    public void getSet(Box<?> box){helper(box);}
  7.  
    public <V> void helper(Box<V> box){box.set(box.get());}
  8.  
    }

5. 有界通配符<? extends XXX>,<? super XXX>

List和List的区别?的更多相关文章

  1. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

  2. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  3. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  4. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  5. X86和X86_64和X64有什么区别?

    x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...

  6. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

  7. MySQL中interactive_timeout和wait_timeout的区别

    在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR (HY000): Lost connection to MySQL server ...

  8. 设置line-height:1.5和line-height:150%或者line-height:150px的区别

    直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...

  9. C#中Length和Count的区别(个人观点)

    这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...

  10. select、poll、epoll之间的区别总结

    select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...

随机推荐

  1. JQuery实现品牌展示

    最近验收了ITOO,老师当时验收的时候对于界面的设计非常敏感,只要看了一个大体轮廓,就能给出我们建议,这是二十年积累的经验,我们要做的就是站在巨人的肩膀上,让我们成长更快! 老师说了一下关于界面设计的 ...

  2. keras模块学习之model层【重点学习】

    本笔记由博客园-圆柱模板 博主整理笔记发布,转载需注明,谢谢合作! model层是keras模块最重要的一个层,所以单独做下笔记,这块比较难理解,本博主自己还在学习这块,还在迷糊中. model的方法 ...

  3. 为什么将项目托管到Apache,浏览器输入http://127.0.0.1会跳转到http://127.0.0.1//dashboard/?

    找到xampp安装的根目录下htdocs文件夹下的index.php文件 <?php if (!empty($_SERVER['HTTPS']) && ('on' == $_SE ...

  4. .NET 中String 和StringBuilder 以及他们的区别

    stirng对象是不可变的,每次使用String类的方法进行运算时(赋值.拼接),都会在内存中生成新的字符串对象,这就要为新对象分配新的内存空间. StringBuilder 实例的 int Capa ...

  5. httpclient: 设置请求的超时时间,连接超时时间等

    httpclient: 设置请求的超时时间,连接超时时间等 public static void main(String[] args) throws Exception{ //创建httpclien ...

  6. composer 发布一个自己的扩展包

    练习写了一个扩展包,步骤参考github项目的readme.md 文件.https://github.com/codingmonkey9/test 说明:只是自己简单记录一下,没有详细写. 如何发布具 ...

  7. Cogs 452. Nim游戏!(博弈)

    Nim游戏! ★ 输入文件:nim!.in 输出文件:nim!.out 简单对比 时间限制:1 s 内存限制:128 MB 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子( ...

  8. mac安装rust

    1.安装 curl https://sh.rustup.rs -sSf | sh 使用brew各种出错,还慢. 2编译 source $HOME/.cargo/env 3.版本查看 rustc --v ...

  9. IDEA控制台乱码终极解决方案

    1. 问题描述 由于本机的IDEA 2019.1出现了无法连接插件商店和Spring Boot模板的问题,就重装了了最新的IDEA 2019.2.4版本,使用了一段时间以后,没有改任何的配置,控制台的 ...

  10. HTML中各标签对应的英文意思

    HTML中各标签对应的英文意思 一.总结 一句话总结: 结合标签的英语全称,可以更加方便的知道标签的意思 二.HTML中标签对应的英文(方便理解记忆)(转自) 转自:HTML中标签对应的英文(方便理解 ...