简体   繁体   English

如何确定在Java中使用哪个通配符?

[英]how to decide which wildcard to use in java?

Where should one use extends, where should one use super, and where is it inappropriate to use a wildcard at all? 一种用途应扩展到哪里,一种用途应扩展到哪里,根本不适合使用通配符?

Is their any principle or rule or it all related to one's own understanding and scope of application. 是他们的任何原则或规则,还是全部与自己的理解和适用范围有关。

Like currently i need only two numbers to add in list so i will used, 像目前一样,我只需要在列表中添加两个数字即可使用,

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

But Later on Scope of my application increase and now it require all numbers, so make it generic for maximum support. 但是后来我的应用程序范围增加了,现在它需要所有数字,因此请使其通用,以获得最大支持。 ex : 例如:

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

In short i just want to know, when should one use these wildcards and when not ? 简而言之,我只想知道,什么时候应该使用这些通配符,什么时候不使用?

I understood the when to use and when not to use and there is one awesome principle i found in one book : 我了解何时使用和何时不使用,我在一本书中发现了一个很棒的原则:

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. 获取和放置原则:仅当从结构中获取值时使用扩展通配符,仅将值放入结构中时使用超级通配符,而同时获取和放置时不使用通配符。

Here is a method that takes a collection of numbers, converts each to a double, and sums them up: 这是一种方法,它采用一组数字,将每个数字转换为双精度数字,然后求和:

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

Since this uses extends, all of the following calls are legal: 由于使用了扩展,因此以下所有调用都是合法的:

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;

The first two calls would not be legal if extends was not used. 如果不使用扩展,则前两个调用将不合法。

EXCEPTION : You cannot put anything into a type declared with an extends wildcard—except for the value null, which belongs to every reference type. 例外:不能将任何东西放入用扩展通配符声明的类型中,除了值null(属于每个引用类型)外。

Whenever you use the add method, you put values into a structure, so use a super wildcard. 每当使用add方法时,都会将值放入结构中,因此请使用超级通配符。 Here is a method that takes a collection of numbers and an integer n, and puts the first n integers, starting from zero, into the collection: 这是一个方法,该方法采用数字和整数n的集合,并将从零开始的前n个整数放入集合中:

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

Since this uses super, all of the following calls are legal: 由于这使用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]");

The last two calls would not be legal if super was not used. 如果不使用super,则最后两个调用将不合法。

EXCEPTION : you cannot get anything out from a type declared with a super wildcard— except for a value of type Object, which is a super type of every reference type. 例外:您无法从使用超级通配符声明的类型中获取任何东西,除了Object类型的值(这是每种引用类型的超级类型)之外。

This principle is also explained in following question Get and Put rule 在以下问题“ 获取和放置”规则中也解释了此原理

You should use them when they make sense... 当它们有意义时,您应该使用它们。

In your instance you said you had to refactor the code to change the generic type to Number from integer due to application evolution. 在您的实例中,您说过由于应用程序的发展,必须重构代码以将通用类型从整数更改为Number。 This is perfectly OK for me. 对我来说这完全可以。 It's nearly impossible to expect all the ways an application may evolve. 几乎不可能期望应用程序的所有发展方式。 Writing code to handle a 'may in the future' scenario is futile until it approaches that time in the future since it may not arrive there at all. 编写代码来处理“将来可能出现”的场景是徒劳的,直到它在将来到达那个时间为止,因为它可能根本没有到达那里。

That being said you should try to design your APIs to the least restricting type the functionality of your function can perform well. 话虽这么说,您应该尝试将API设计为最少限制的类型,以使您的功能可以正常运行。 Unless of course it will require considerably more effort and current functionality have no use for the flexibility being offered. 除非当然需要大量的工作,否则当前的功能将无法提供所提供的灵活性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM