这是对 Explanation of Collections.max()
signature 的后续问题,其中接受的答案没有深入探讨此通配符的实际原因。
max
方法需要一个 Collection<? extends T>
我想不出这个通配符有帮助的实际案例。
我什至提到了Oracle More fun with wildcards它指出
In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T). Conversely, if the API only returns T, you'll give your clients more flexibility by using upper bounded wildcards (? extends T).
但是我还是没看懂。连Java Generics and Collections书中并没有过多讲述这个通配符背后的原因。
这个有实际用途吗?真实世界的用例会很棒。
最佳答案
想象一下这两个签名:
static <T extends Object & Comparable<? super T>> T max1(Collection<T> coll);
static <T extends Object & Comparable<? super T>> T max2(Collection<? extends T> coll);
现在,让我们尝试构造类型函数。
Function<Collection<java.sql.Timestamp>, java.util.Date>
// This doesn't work:
Function<Collection<Timestamp>, Date> f0 =
(Collection<Timestamp> col) -> Test.<Date>max1(col);
// This works:
Function<Collection<Timestamp>, Date> f1 =
(Collection<Timestamp> col) -> Test.<Date>max2(col);
如您所见,使用显式键入,其中一种方法不再有效。
类型推断在“现实世界”中“隐藏”了这个问题:
当然,您可以省略泛型类型参数的显式绑定(bind) Test.<Date>maxN()
:
Function<Collection<Timestamp>, Date> f0 =
(Collection<Timestamp> col) -> Test.max1(col);
Function<Collection<Timestamp>, Date> f1 =
(Collection<Timestamp> col) -> Test.max2(col);
甚至:
Function<Collection<Timestamp>, Date> f2 = Test::max1;
Function<Collection<Timestamp>, Date> f3 = Test::max2;
并且类型推断会发挥它的魔力,因为上面所有的编译。
现在何必呢?
我们应该始终关心 API 的一致性,因为 pbabcdefp has said in his answer .想象一下还有一个额外的 optionalMax()
方法(只是为了处理空参数集合的情况):
static <T extends ...> Optional<T> optionalMax1(Collection<T> coll);
static <T extends ...> Optional<T> optionalMax2(Collection<? extends T> coll);
现在,您可以清楚地看到只有第二种变体有用:
// Does not work:
Function<Collection<Timestamp>, Optional<Date>> f0 =
(Collection<Timestamp> col) -> Test.optionalMax1(col);
Function<Collection<Timestamp>, Optional<Date>> f2 = Test::max1;
// Works:
Function<Collection<Timestamp>, Optional<Date>> f1 =
(Collection<Timestamp> col) -> Test.optionalMax2(col);
Function<Collection<Timestamp>, Optional<Date>> f3 = Test::optionalMax2;
考虑到这一点,以下 API 会感觉非常不一致,因此是错误的:
static <T extends ...> T max(Collection<T> coll);
static <T extends ...> Optional<T> optionalMax(Collection<? extends T> coll);
因此,为了保持一致(无论是否需要输入),方法应该使用Collection<? extends T>
签名。总是。
关于java - Collections.max() 签名的实际使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30012669/