Java Collections.max签名的说明
我在读一篇关于Java泛型的文章时偶然发现了这个方法签名:Java Collections.max签名的说明,java,generics,Java,Generics,我在读一篇关于Java泛型的文章时偶然发现了这个方法签名: static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll); staticGábor是正确的。通配符允许返回对象的静态类型与您输入的集合的声明参数类型不同。例如,给定这些类: interface S extends Comparable<S> {} class A im
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);
staticGábor是正确的。通配符允许返回对象的静态类型与您输入的集合的声明参数类型不同。例如,给定这些类:
interface S extends Comparable<S> {}
class A implements S {
@Override
public int compareTo(final @NotNull S o) {
return 0;
}
}
class B implements S {
@Override
public int compareTo(final @NotNull S o) {
return 0;
}
}
由于add()
,remove()
,以及Collection
接口中的大多数其他变体都是可选操作,因此,如果参数仅声明为集合,则通过这些方法对集合进行任何变体都是不安全的。此外,通常可以使用iterator().remove()
或类似的方法从集合中删除元素,而不管它们是否使用通配符声明,尤其是对于已经包含在Java集合框架中的元素
因此,虽然通配符确实限制了对集合的操作,但不应将其用作阻止对集合进行更改的方法。例如,您希望返回一个数字
,但您也希望使用双精度
或整数
集合。通过这种方式,您可以在呼叫站点指定电话号码:max(doubles)
。感谢您的回复。但是,我认为如果我们将Collection作为参数,这仍然有效。我的怀疑是,在这种情况下,使用CollectionUsing通配符的唯一区别在于,它可以防止该方法无意中添加到集合或以其他方式改变集合,因为消费者需要super(始终记住PECS助记符!)您还可以看到它遵循PECS原则。Coll是T的提供者,因此它使用extendsTest。max(aColl);//不编译
当然不编译T=S
,而aColl
是Collection
。但是正如您在后面提到的,您不需要使用
来显式地t
true<因为aColl
,code>T
将是A
,而不是S
因为作业。不管怎样,我现在明白了。谢谢你的详细回复!谢谢@user3580294。它以一种更清晰的方式呈现。我还忘记了变异的remove
方法。@GáborBakosCollections.swap(…)
或Collections.sort(…)
也可以使用通配符类型。还有clear()
删除所有元素。
Collection<T> coll
static <T extends Object & Comparable<? super T>> T max(Collection<T> coll);
interface S extends Comparable<S> {}
class A implements S {
@Override
public int compareTo(final @NotNull S o) {
return 0;
}
}
class B implements S {
@Override
public int compareTo(final @NotNull S o) {
return 0;
}
}
class Test {
@Nullable
static <T extends Comparable<? super T>> T extendsMax(
Collection<? extends T> coll) {
return null;
}
@Nullable
static <T extends Comparable<? super T>> T max(Collection<T> coll) {
return null;
}
}
public static void main(String[] args) {
final Collection<S> sColl = new ArrayList<>();
final Collection<A> aColl = new ArrayList<>();
final Collection<B> bColl = new ArrayList<>();
final S s1 = Test.<S> extendsMax(sColl); // compiles, T = S, <? extends T> = S
final S s2 = Test.<S> extendsMax(aColl); // compiles, T = S, <? extends T> = A
final S s3 = Test.<S> extendsMax(bColl); // compiles, T = S, <? extends T> = B
final A a1 = Test.<A> extendsMax(aColl); // compiles, T = A
final B b1 = Test.<B> extendsMax(bColl); // compiles, T = B
final S s4 = Test.<S> max(sColl); // compiles, T = S
final S s5 = Test.<S> max(aColl); // does not compile, T = S, T != A
final S s6 = Test.<S> max(bColl); // does not compile, T = S, T != B
final S s7 = Test.max(aColl); // compiles, but because T = A, and A
// can be assigned to S
}
List<? extends Number> list = new ArrayList<>();
list.add(null); // compiles, and should execute just fine