【问题标题】:Java Generic type : difference between List <? extends Number> and List <T extends Number>Java 泛型类型:List <? extends Number> 和 List <T extends Number>
【发布时间】:2013-08-13 18:22:13
【问题描述】:

Java 泛型类型:有什么区别

(1) List <? extends Number>   
(2) List <T extends Number>

据我了解

(1) List &lt;? extends Number&gt; 是 具有超类“数字”的“未知”数据类型的只读列表。我们只能读取元素但不能添加

(2)List &lt;T extends Number&gt; 具有超类“数字”的数据类型列表。我们可以读取并添加元素到列表中

请看下面的代码示例

class TestGen{

    public static void main(String[] args) {
        double result = 0.0;

        List<Integer> intList = new ArrayList<Integer>();
        intList.add(10);
        intList.add(20);
        intList.add(30);

        result = TestGen.sumOfList1(intList);
        System.out.println("Result=" + result);
        result = TestGen.sumOfList2(intList);
        System.out.println("Result=" + result);
    }

    public static double sumOfList1(List<? extends Number> list) {
        double s = 0.0;
        for (Number n : list)
            s += n.doubleValue();
        return s;
    }

    public static <T extends Number> double sumOfList2(List<T> list) {
        double s = 0.0;

        // getting error while trying to add new element 
        // list<T> is not applicable for argument(Integer) : Why ?
        list.add(new Integer(40));

        for (Number n : list)
            s += n.doubleValue();

        return s;
    }
}

当我尝试将 Integer(甚至 Number 对象)添加到 sumOfList2 中时,会出现错误。请解释这里有什么问题?

【问题讨论】:

    标签: java


    【解决方案1】:

    基本区别是如果你使用T extends Number,那么你可以引用T的类型:
    list.add((T) new Integer(40));

    如果你使用? extends Number,那么你可以引用类型,但你仍然可以说:
    ((List&lt;Integer&gt;)list).add((int) s);

    【讨论】:

    • 不确定谁投了反对票....这个解决方案有效,请您说明为什么需要强制转换。 list.add((T) 新整数(40));而我们只添加子类的对象(整数是数字的子类)
    • 我猜当你将它投射到 T 时,它会给你 type safety 警告。
    • 我猜,根据参数的类型,List 可以接受 T 类型的值,因此您需要将 add() 的参数强制转换为 T
    【解决方案2】:

    单独来看,没有太大区别。但是,单个上下文中的两个List&lt;? extends Number&gt; 实例完全不相关,而单个上下文中的两个List&lt;T extends Number&gt; 实例引用相同的T 和相同的接口。

    public void addAll(List<? extends Number> to, List<? extends Number> from) {
        for (Number n: from) {
            to.add(n);
        }
    }
    

    这个方法失败是因为n不能添加到to,也因为fromto的成员类型可以完全不同而失败。

    public <T> void addAll(List<T extends Number> to, List<T extends Number> from) {
        for (T n: from) {
            to.add(n);
        }
    }
    

    这个方法编译得很好。没有必要; Collections 有更好的版本,但是运行起来不会出错。

    【讨论】:

    • 事实上addAll(List&lt;T extends Number&gt; to, ... 甚至无法编译。必须是&lt;T extends Number&gt; void addAll(List&lt;T&gt; to, ...
    【解决方案3】:

    sumOfList2 中,TNumber 的特定子类,但它可以是其中的任何一个。例如T 可以是BigDecimal,您不能将Integer 添加到List&lt;BigDecimal&gt;

    如果您希望能够将任何类型的数字添加到列表中,它必须是List&lt;Number&gt;

    public static double sumOfList2(List<Number> list) {...}
    

    【讨论】:

      【解决方案4】:

      第一种情况非常简单,从T extends Number 得知 T 是一个 Object 类型,它是 Number 类或其子类。 这意味着如果我们有一个使用 T 作为 Number 类型的方法,我们可以相应地操作我们的方法,即

      <T extends Number> void myMethod ( List <T> num){
           num.add(1); // 1 is an Integer
           num.add(2.3) // 2.3 is a Double
      } 
      

      但是在这个 *Wild 字符 '?' * 即使它扩展了 Number,我们也不知道要引用哪种类型的 Object,但它可以是任何类型的 Object

      void myMethod( List <? extends Number> num){
           // num.add(1); // not a valid statement, as we dont know if '1' is of the type '?'
           // num.add(2.3)  // not a valid statement, as we dont know if '2.3' is of the type '?'
      }
      

      因此,可以在此类语句中写下的唯一值是 null,因为任何类型的 Object 都可以为 null。

          void myMethod( List <? extends Number> num){
            num.add(null)
          }
      

      此类方法是只读方法。

      【讨论】:

      • 您的第一个示例实际上无法编译。
      【解决方案5】:

      1)

      List <? extends Number> 
      

      用起来比较合适

      List<Integer> list = Arrays.asList(0,1,2,3,4);
      

      这不会给您带来错误。

      List <Double> list = Arrays.asList(0.0,0.1,0.2,0.3,0.4);
      

      然后你可以添加到

      result = TestGen.sumOfList1(list);
      

      2) 列表

      List<Integer> list = new ArrayList<Integer>();
      list.add(0);
      list.add(1); Would do the job.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-17
        • 1970-01-01
        • 1970-01-01
        • 2017-05-21
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多