"<E extends Number>" 和 "<Number>" 有什么区别?(注:涉及 IT 技术)

46

这个方法声明的区别是什么:

public static <E extends Number> List<E> process(List<E> nums){

并且

 public static List<Number> process(List<Number> nums){

你会在哪里使用前者?

2个回答

62

第一个允许处理List<Integer>List<Double>等类型的process,而第二个则不行。

Java中的泛型是不变的。它们不像数组一样是协变的。

也就是说,在Java中,Double[]Number[]的子类型,但是List<Double>不是List<Number>的子类型。然而,List<Double>List<? extends Number>的子类型。

有很好的理由让泛型保持不变,但这也是为什么extendssuper类型经常需要用于子类型灵活性的原因。

另请参阅


1
我认为解释一下这两种方法的区别也是很好的,例如:<E extends Number> E process(E elt)Number process(Number elt) - Vic Seedoubleyew

16
< p >后一种方法(不带<E extends Number>)只接受完全类型为List<Number>的参数,并且它始终返回List<Number>。例如,它将不会接受List<Integer>

前一种方法(带有<E extends Number>)是一种泛型方法,意味着它可以接受不同类型的List并且它将返回相同类型的List,只要这些List都是扩展了Number的东西,例如List<Integer>

例:

import java.util.ArrayList;
import java.util.List;

public class ProcessGenerics {

    List<Number>  listNumber  = new ArrayList<Number>();
    List<Integer> listInteger = new ArrayList<Integer>();
    List<Double>  listDouble  = new ArrayList<Double>();


    public static
        List<Number> processWithoutExtends(List<Number> nums){ return nums; }

    List<Number>  resultN = processWithoutExtends(listNumber);  // OK
  //List<Integer> resultI = processWithoutExtends(listInteger); // compile-error - method not applicable
  //List<Double>  resultD = processWithoutExtends(listDouble);  // compile-error - method not applicable


    public static <E extends Number>
        List<E> processWithExtends(List<E> nums){ return nums; }

    List<Number>  resultN2 = processWithExtends(listNumber);  // OK
    List<Integer> resultI2 = processWithExtends(listInteger); // OK
    List<Double>  resultD2 = processWithExtends(listDouble);  // OK

}

在Java教程的泛型课程中的通配符章节中,可以看到类似的解释:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html

同时,也可以参考如何将一组继承对象强制转换为Java中对象的集合?。这两个问题都涉及到泛型和子类型,例如 List<Integer> 是否是 List<Number> 的子类型(它不是!)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接