java钻石表达式_泛型 - Java 7中的钻石运算符有什么意义?

泛型 - Java 7中的钻石运算符有什么意义?

java 7中的菱形运算符允许如下代码:

List list = new LinkedList<>();

但是在Java 5/6中,我可以简单地写:

List list = new LinkedList();

我对类型擦除的理解是这些完全相同。 (无论如何,通用都会在运行时删除)。

为什么要钻石头呢? 它允许哪些新功能/类型安全? 如果它没有产生任何新功能,为什么他们将其作为功能提及? 我对这个概念的理解有缺陷吗?

7个解决方案

462 votes

这个问题

List list = new LinkedList();

在左侧,您使用的是通用类型<>,在右侧您使用的是原始类型Collection. Java中的原始类型实际上只存在与前泛型代码的兼容性,不应在新代码中使用 除非你绝对必须这样做。

现在,如果Java从一开始就具有泛型,并且没有类型,例如<>,它们最初是在具有泛型之前创建的,它可能已经使得它使得泛型类型的构造函数自动从其中推断出它的类型参数。 如果可能的话,分配的左侧。 但事实并非如此,它必须以不同的方式处理原始类型和泛型类型以实现向后兼容性。 这使得他们需要制作一种稍微不同但同样方便的方式来声明一个通用对象的新实例,而不必重复其类型参数......菱形运算符。

至于您的原始示例<>,编译器会为该分配生成警告,因为它必须。 考虑一下:

List strings = ... // some list that contains some strings

// Totally legal since you used the raw type and lost all type checking!

List integers = new LinkedList(strings);

存在泛型以提供编译时保护以防止做错事。 在上面的示例中,使用原始类型意味着您没有获得此保护,并且在运行时将收到错误。 这就是你不应该使用原始类型的原因。

// Not legal since the right side is actually generic!

List integers = new LinkedList<>(strings);

但是,菱形运算符允许将赋值的右侧定义为具有与左侧相同类型参数的真正通用实例...而无需再次键入这些参数。 它允许您使用与原始类型几乎相同的努力来保持泛型的安全性。

我认为要理解的关键是原始类型(没有<>)不能与泛型类型相同。 当您声明原始类型时,您将无法获得泛型的任何好处和类型检查。 您还必须记住,泛型是Java语言的通用部分......它们不仅适用于Collections的无参数构造函数!

ColinD answered 2019-01-07T06:51:34Z

34 votes

你的理解有点缺陷。 钻石操作员是一个很好的功能,因为你不必重复自己。 在声明类型时定义类型一次是有意义的,但在右侧再次定义它是没有意义的。 干旱原则。

现在解释关于定义类型的所有模糊。 你是正确的,在运行时删除了类型,但是一旦你想要从具有类型定义的List中检索某些东西,你就会将它作为你在声明列表时定义的类型返回,否则它将丢失所有特定的功能并且只有 对象功能,除非您将检索到的对象强制转换为原始类型,这有时会非常棘手并导致ClassCastException。

使用List list = new LinkedList()将获得rawtype警告。

Octavian Damiean answered 2019-01-07T06:52:16Z

15 votes

此行导致[未选中]警告:

List list = new LinkedList();

因此,问题转换:为什么[unchecked]警告不会仅在创建新集合时自动被抑制?

我认为,添加<>功能将会困难得多。

UPD:我还认为如果合法地使用原始类型“只是为了一些东西”会有一团糟。

Roman answered 2019-01-07T06:53:03Z

13 votes

理论上,菱形运算符允许您通过保存重复的类型参数来编写更紧凑(和可读)的代码。 在实践中,它只是两个令人困惑的角色更多的东西给你什么。 为什么?

没有理智的程序员在新代码中使用原始类型。 因此,编译器可以简单地假设通过编写没有类型参数,您希望它推断它们。

钻石运算符不提供类型信息,它只是说编译器,“它会没事”。 因此,通过省略它你就不会有任何伤害。 在钻石操作符合法的任何地方,编译器都可以“推断”它。

恕我直言,有一个清晰简单的方法将源标记为Java 7比发明这些奇怪的东西更有用。 在如此标记的代码中,原始类型可能被禁止而不会丢失任何东西。

顺便说一句,我认为不应该使用编译开关来完成。 程序文件的Java版本是文件的属性,根本没有选项。 使用像微不足道的东西

package 7 com.example;

可以说清楚(你可能更喜欢更复杂的东西,包括一个或多个花哨的关键词)。 它甚至允许编译为不同Java版本编写的源代码而没有任何问题。 它将允许引入新的关键字(例如,“模块”)或丢弃一些过时的特征(在单个文件中或在任何情况下的多个非公共非嵌套类)而不会失去任何兼容性。

maaartinus answered 2019-01-07T06:54:11Z

7 votes

当您编写List list = new LinkedList();时,编译器会生成“未选中”警告。 您可以忽略它,但如果您曾经忽略这些警告,您可能还会错过警告,通知您有关真正的类型安全问题。

因此,编写一个不会产生额外警告的代码会更好,而菱形运算符允许您以方便的方式执行此操作而无需不必要的重复。

axtavt answered 2019-01-07T06:54:42Z

4 votes

所有在其他回复中说的都是有效的,但用例并不完全有效恕我直言。 如果检查Guava,特别是与集合相关的东西,那么静态方法也是如此。 例如。 Lists.newArrayList()允许你写

List names = Lists.newArrayList();

或者使用静态导入

import static com.google.common.collect.Lists.*;

...

List names = newArrayList();

List names = newArrayList("one", "two", "three");

Guava还有其他非常强大的功能,我实际上无法想到&lt;&gt;的多少用途。

如果他们将菱形操作符行为设置为默认值,也就是说,从表达式的左侧推断出类型,或者如果左侧的类型是从右侧推断的,则会更有用。 后者是Scala中发生的事情。

allprog answered 2019-01-07T06:55:36Z

3 votes

菱形运算符的要点只是在声明泛型类型时减少代码的类型。 它对运行时没有任何影响。

如果您在Java 5和6中指定唯一的区别,

List list = new ArrayList();

是你必须指定@SuppressWarnings("unchecked")到list(否则你将得到一个未选中的强制转换警告)。 我的理解是钻石操作员正在努力使开发更容易。 根本没有关于泛型的运行时执行的任何事情。

Buhake Sindi answered 2019-01-07T06:56:20Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值