java - java中如何决定使用哪个通配符?

标签 java generics collections wildcard

哪里应该使用extends,哪里应该使用super,哪里不适合使用通配符?

它们到底是什么原理或者规则还是都与自己的理解和适用范围有关。

就像目前我只需要在列表中添加两个数字,所以我会使用,

 public List<Integer> addToNewList(integerList  , Integer element){
   integerList.add(element);
   return integerList;
}

但是后来我的应用程序范围增加了,现在它需要所有数字,因此使其通用以获得最大支持。 例如:

public <T extends Number> List<T> addToList(List<? extends T> genericList , T element){
   genericList.add(element);
   return genericList;
}

简而言之,我只是想知道,什么时候应该使用这些通配符,什么时候不应该使用?

最佳答案

我了解何时使用和何时不使用,并且我在一本书中发现了一个很棒的原则:

The Get and Put Principle: use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don’t use a wildcard when you both get and put.

下面是一个方法,它接受数字集合,将每个数字转换为 double 型,然后将它们相加:

public static double sum(Collection<? extends Number> nums) {
    double s = 0.0;
    for (Number num : nums) s += num.doubleValue();
    return s;
}

由于使用了扩展,因此以下所有调用都是合法的:

List<Integer>ints = Arrays.asList(1,2,3);
assert sum(ints) == 6.0;
List<Double>doubles = Arrays.asList(2.78,3.14);
assert sum(doubles) == 5.92;
List<Number>nums = Arrays.<Number>asList(1,2,2.78,3.14);
assert sum(nums) == 8.92;

如果不使用扩展,前两个调用将不合法。

异常(exception):您不能将任何内容放入使用扩展通配符声明的类型中,除了值 null,它属于每个引用类型。

每当您使用 add 方法时,您都会将值放入结构中,因此请使用 super 通配符。这是一个接受数字集合和整数 n 的方法,并且 将前 n 个整数(从零开始)放入集合中:

public static void count(Collection<? super Integer> ints, int n) {
    for (int i = 0; i < n; i++) ints.add(i);
}

由于这里使用了 super,因此以下所有调用都是合法的:

List<Integer>ints = new ArrayList<Integer>();
count(ints, 5);
assert ints.toString().equals("[0, 1, 2, 3, 4]");
List<Number>nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
List<Object>objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
assert objs.toString().equals("[0, 1, 2, 3, 4, five]");

如果不使用 super,最后两个调用将不合法。

异常(exception):您无法从使用 super 通配符声明的类型中获取任何内容 - 但 Object 类型的值除外,它是每个引用类型的父类(super class)型。

这个原理在下面的问题 Get and Put rule 中也有解释。

关于java - java中如何决定使用哪个通配符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18585366/

相关文章:

java - 调用静态方法时如何指定泛型类型?

java - fragment 转换的问题

c# - 可变长度参数 c#

c# - 在 C# 中将对象 T 转换为 List<T>

java - 管理集合映射的通用方法

java - 使用 Thymeleaf 实现 JPA 验证消息国际化

java - 什么是原始类型,为什么我们不应该使用它呢?

java - JAXB 如何猜测列表的模式类型?

java - 如果我的 hashCode() 很弱,在 ConcurrentHashMap 中设置 concurrencyLevel 有什么帮助?

java - 如何在Java中使用HTML响应来提取数据?