请考虑以下来自Shiro org.apache.shiro.subject.PrincipalCollection界面的API方法,但可能也存在于其他库中:
Collection fromRealm(String realmName);
Run Code Online (Sandbox Code Playgroud)
是的,即使是现在,仍然有一些库使用原始类型,可能是为了保留Java 1.5之前的兼容性?
如果我现在想将此方法与流或类似的可选项一起使用:
principals.fromRealm(realmName).stream().collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)
我收到有关未经检查的转换和使用原始类型的警告,我应该更喜欢使用参数化类型。
日食:
类型安全:方法collect(Collector)属于原始类型Stream。泛型类型Stream <T>的引用应参数化
javac:
注意:GenericsTest.java使用未经检查或不安全的操作。
由于我无法更改API方法的签名来摆脱此警告,因此我可以使用以下注释@SuppressWarnings("unchecked")或将其强制转换为Collection<?>:
((Collection<?>) principals.fromRealm(realmName)).stream().collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)
由于这种转换当然总是有效,所以我想知道为什么编译器不只是简单地将其Collection视为Collection<?>而是警告这种情况。添加注释或强制转换不会单单提高代码,但会降低可读性,甚至可能掩盖有关使用非参数类型的实际有效警告。
Lin*_*ica 70
原因很简单:
您可能以Object与from Collection<?>相同的方式阅读Collection。但是您不能将Objects 添加到Collection<?>(编译器禁止这样做),而Collection可以添加。
如果在Java 5发行后,编译器已将每次转换Collection为Collection<?>,则先前编写的代码将不再编译,因此将破坏向后兼容性。
Ond*_* K. 19
原始类型和无界通配符之间的主要区别在于<?>后者是安全类型,即在编译级别,它检查集合中的项目是否属于同一类型。编译器不会让你的字符串和整数添加到通配符类型的集合,但它会允许你这样做:
List raw = new ArrayList();
raw.add("");
raw.add(1);
Run Code Online (Sandbox Code Playgroud)
实际上,在无限制的通配符集合(List<?> wildcard = new ArrayList<String>())的情况下,您什么都不能添加到列表中,而只能null从Oracle文档中添加:
由于我们不知道c的元素类型代表什么,因此无法向其添加对象。add()方法采用类型E(集合的元素类型)的参数。当实际类型参数为?时,代表某种未知类型。我们传递来添加的任何参数都必须是该未知类型的子类型。由于我们不知道是什么类型,因此无法传递任何内容。唯一的例外是null,它是每种类型的成员。
一个Collection<?>尖叫:
请不要向我添加任何东西。我有一个严格的内容类型,......嗯,我只是忘记了它是什么类型。
而 aCollection说:
这一切都很酷!你可以添加任何你喜欢的,我没有限制。
那么,为什么编译器不应该转换Collection为Collection<?>?因为它会设置很多限制。