Java 为什么不简单地将收藏视为收藏<&燃气轮机;
考虑以下API方法,该方法取自Shiro的接口,但也可能存在于其他库中:Java 为什么不简单地将收藏视为收藏<&燃气轮机;,java,generics,Java,Generics,考虑以下API方法,该方法取自Shiro的接口,但也可能存在于其他库中: Collection fromRealm(String realmName); 是的,即使是现在,仍然有库使用原始类型,可能是为了保持Java1.5之前的兼容性 如果我现在想将此方法与以下流或选项一起使用: principals.fromRealm(realmName).stream().collect(Collectors.toSet()); ((Collection<?>) principals.fro
Collection fromRealm(String realmName);
是的,即使是现在,仍然有库使用原始类型,可能是为了保持Java1.5之前的兼容性
如果我现在想将此方法与以下流或选项一起使用:
principals.fromRealm(realmName).stream().collect(Collectors.toSet());
((Collection<?>) principals.fromRealm(realmName)).stream().collect(Collectors.toSet());
我得到一个关于未经检查的转换和使用原始类型的警告,我更喜欢使用参数化类型
月食:
类型安全:方法collect(收集器)属于原始类型流。对泛型类型流的引用应该参数化
爪哇语:
注意:GenericsTest.java使用未经检查或不安全的操作
由于我无法更改API方法的签名以消除此警告,因此我可以使用@SuppressWarnings(“unchecked”)
进行注释,或者简单地强制转换为集合
,如下所示:
principals.fromRealm(realmName).stream().collect(Collectors.toSet());
((Collection<?>) principals.fromRealm(realmName)).stream().collect(Collectors.toSet());
((Collection)principals.fromRealm(realmName)).stream().collect(Collectors.toSet());
当然,由于这种类型转换总是有效的,我想知道为什么编译器不简单地将
Collection
视为Collection
,而是警告这种情况。添加注释或强制转换不会提高代码的可读性,但会降低代码的可读性,甚至可能会掩盖有关使用未参数化类型的实际有效警告。原因很简单:
您可以从集合
读取对象
s,方法与从集合
读取相同但是您不能将对象
添加到集合
(编译器禁止此操作),而可以将对象添加到集合
如果Java 5发布后,编译器已将每个集合
翻译为集合
,然后,以前编写的代码将不再编译,因此将破坏向后兼容性。我可以想到的一个用例是,Collection
不被视为Collection
,假设我们有一个ArrayList
现在,如果实例的类型为ArrayList
或ArrayList
或ArrayList
,则只能添加该类型(类型检查)ArrayList
不等同于ArrayList
但仅使用ArrayList
,就可以添加任何类型的对象。这可能是编译器不将ArrayList
视为ArrayList
(类型检查)的原因之一
另一个原因可能是与没有泛型的Java版本的向后兼容性。原始类型和无界通配符之间的主要区别在于后者是类型安全的,也就是说,在编译级别上,它检查集合中的项是否属于同一类型。编译器不允许您将字符串和整数添加到通配符类型的集合中,但允许您执行以下操作:
List raw = new ArrayList();
raw.add("");
raw.add(1);
实际上,对于无限通配符集合(List wildcard=new ArrayList()
),除了null
(从)之外,您不能向列表中添加任何内容:
因为我们不知道c的元素类型代表什么,所以我们不能向它添加对象。add()方法接受类型为E的参数,即集合的元素类型。当实际类型参数为?时,它表示某个未知类型。我们传递要添加的任何参数都必须是此未知类型的子类型。因为我们不知道那是什么类型,所以我们不能传递任何信息。唯一的异常是null,它是每种类型的成员
一个集合
尖叫:
请不要给我添加任何内容。我有一个严格的内容类型。。。嗯,我只是忘了它是什么类型的
而集合
表示:
一切都很酷!你可以随意添加,我没有任何限制
那么,为什么编译器不应该将集合
转换为集合
?
因为它会有很多限制。问号类型有点棘手。它可以是任何东西,例如集合x;集合y;并不意味着x可以被转换成y,因为它可以是不同的。EGx=新的ArrayList();y=新的ArrayList()Collection
并不等同于Collection
,它更接近Collection
。@immibis这是一个太强的说法。您可以将null
插入集合
。请参见alse@dpr事实上,问题在于Java没有“只读”构造的概念,因此泛型类型系统对于流API没有不同的行为方式。然而,有一些调整。给定一个集合c
,您可以编写集合c2=Collections.unmodifiableCollection(c)代码>没有问题,正如库设计人员所知道的那样,他们阻止在结果中插入对象
到通用签名中的任何尝试。我刚刚注意到,“保持Java 1.5之前的兼容性”不能成为在这里使用原始类型的理由。该接口有两个通用方法。另一个方法,getRealmNames()
被声明为返回Set
“[unbounded wildcard]是类型安全的,也就是说,在编译级别上,它检查集合中的项是否属于同一类型。”-哼?!这与你其余的答案相矛盾或者不完全是这样;可以说它是类型安全的,因为它不允许将任何对象放入
集合中。编译器根本不检查泛型集合中的内容。相反,它对其构造函数和方法的(声明的)参数类型以及对其方法返回值的类型的期望进行检查。除此之外:Collection
不是“任何类型的集合”。它是“某种类型的集合,但该类型未知。”这就是为什么不能向其中添加非null对象