Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么不简单地将收藏视为收藏<&燃气轮机;_Java_Generics - Fatal编程技术网

Java 为什么不简单地将收藏视为收藏<&燃气轮机;

Java 为什么不简单地将收藏视为收藏<&燃气轮机;,java,generics,Java,Generics,考虑以下API方法,该方法取自Shiro的接口,但也可能存在于其他库中: Collection fromRealm(String realmName); 是的,即使是现在,仍然有库使用原始类型,可能是为了保持Java1.5之前的兼容性 如果我现在想将此方法与以下流或选项一起使用: principals.fromRealm(realmName).stream().collect(Collectors.toSet()); ((Collection<?>) principals.fro

考虑以下API方法,该方法取自Shiro的接口,但也可能存在于其他库中:

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对象