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

时间:2013-09-03 06:16:36

标签: java generics collections wildcard

应该在哪里使用扩展,哪里应该使用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;
}

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

2 个答案:

答案 0 :(得分:4)

我知道何时使用以及何时不使用,我在一本书中找到了一个很棒的原则:

  

获取和放置原则:只在您获得时使用扩展通配符   结构中的值,当你只放置时使用超级通配符   将值放入结构中,并且当两者都得到时不要使用通配符   并把。

这是一个方法,它采用一组数字,将每个数字转换为一个数字,并将它们相加:

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: 您无法从使用超级通配符声明的类型中获取任何内容 - 除了Object类型的值,它是每个引用类型的超类型。

以下问题Get and Put rule

也解释了这一原则

答案 1 :(得分:2)

你应该在有意义时使用它们......

在您的实例中,您说由于应用程序的演变,您必须重构代码以将泛型类型从整数更改为Number。这对我来说完全没问题。几乎不可能期望应用程序可能发展的所有方式。编写代码来处理“将来可能”的情况是徒劳的,直到它将来接近那个时间,因为它可能根本不会到达那里。

话虽如此,您应该尝试将API设计为限制性最小的类型,但功能的功能可以很好地运行。除非它当然需要更多的努力,并且当前的功能对于提供的灵活性没有用处。