钻石操作符<>是否等同于<?>?

13

我在util.TreeSet类中发现其中一个构造函数调用了另一个构造函数,使用了一个空泛型的新TreeMap

  public TreeSet(Comparator<? super E> comparator) {
         this(new TreeMap<>(comparator));
  }

new TreeMap<>的意思是创建一个没有显式泛型类型参数的TreeMap实例,而new TreeMap<?>则等同于创建一个带有通配符泛型类型参数的TreeMap实例。


5
回答:https://dev59.com/EWoy5IYBdhLWcg3wQ8AF这个问题询问了Java泛型中的"?"符号的含义。在Java泛型中,"?"被用作通配符类型参数,表示可以匹配任何类型。它是一种限制通配符,可以用来强制执行类型安全。 - davidmontoyago
让我稍微修改一下我的标题。 - peter
2
new TreeMap<?>()甚至都不是有效的。 - newacct
2个回答

18

这是Java 7的语法。钻石符号(<>)是一种简写方式,要求Java编译器根据本地上下文填充泛型参数(在本例中,它将是? super E)。


生成的字节码是向后兼容的,因为Javac只是为你填充。源文件需要使用JDK 7编译。 - Romain
2
@user1389813,使用 Diamond 的代码等同于 Java 7 中的 <? super E>。如果您使用 Java 6 或更低版本进行编译,将会出现编译器错误。 - Luiggi Mendoza
1
从技术上讲,由于类型擦除,实际上没有什么需要填充的。相反,它不检查类型。如果您有一个必须填写的类型,例如匿名子类,则无法使用<> - Peter Lawrey
2
在这种情况下,它将是? super E。不,new TreeMap<? super E>()是无效的。 - newacct
1
@user1389813:从某个层面上来说,你可以说它可以“填充”括号中满足边界的任何内容(在这种情况下,任何E的子类型都可以;最简单的是E本身)。但正如Peter Lawrey所说,由于不同类型参数生成的代码没有区别,编译器并不真正关心要“填充”什么。 - newacct
显示剩余2条评论

4
不,<?><>不是一样的。 <?>是“无界通配符”,自Java 5以来就存在了。这个通配符允许(即匹配)任何类型绑定允许的内容,没有额外的限制。通配符的代价是您可以对泛型实例进行的操作。有关通配符的更多信息,请阅读Java教程部分。要了解哪些通配符允许哪些类型限制,请查看此博客
"<>"是钻石操作符,在Java 7中添加。目标是通过在调用构造函数时从上下文中推断出这些类型,使开发人员免于不必要地冗长地创建泛型类型的实例。
编译器尽可能推断最具体的类型,考虑以下因素(如果可用):
1-传递给构造函数的参数类型。
2-分配新实例的引用中指定的类型(“=”赋值的左侧部分)。
3-类型的擦除。
在您的示例中,编译器将使用new TreeMap<>(comparator)替换为new TreeMap<E,Object>(comparator)
要了解原因,请查看正在调用的TreeMap<K,V>构造函数:TreeMap(Comparator<? super K> comparator)
编译器需要推断KV的类型。它期望一个Comparator<? super K>,并发现传递了一个Comparator<? super E>,没有左侧分配,编译器不会对将E分配给K(任何与E匹配的内容都会匹配一个K,因为它们具有相同的擦除),它得出结论K=E
对于V,同样没有左侧分配,没有传递给构造函数的参数,因此留下了在TreeMap<K,V>中指定的类型V的擦除,其擦除为Object,因此得出结论V=Object
这就是它的全部,编译器推断K=EV=Object,语句变为TreeMap<E,Object>(comparator)
值得一提的是,虽然钻石操作符可以推断出正在创建的实例的泛型类型,但它不会推断出构造函数的泛型类型(如果构造函数是泛型的),因为构造函数可以像定义泛型方法一样使用泛型类型变量(您可以添加未在类中定义的其他类型),而这些类型也会受到编译器的推断,类似于它对泛型方法推断类型的方式,而不是通过钻石操作符。

1
实际上,编译器不需要推断任何东西——括号内的内容对编译后的字节码没有影响。 - newacct
@newacct True,编译后的字节码不受影响。但是在上述情况下,编译器将“处理”TreeMap<>,就好像它被写成了TreeMap<E,Object>一样。实际上,上面的TreeSet(Comparator)构造函数调用了另一个以NavigableMap<E,Object>为参数的TreeSet构造函数。 - Asem Abusbeit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接