Java 7中钻石操作员的要点是什么?(What is the point of the diamond operator (<>) in Java 7?)

java 7中的钻石操作符允许代码如下:

List<String> list = new LinkedList<>();

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

List<String> list = new LinkedList();

我对类型擦除的理解是这些完全一样。 (一般在运行时被删除)。

为什么要打钻石呢? 它允许什么新的功能/类型的安全? 如果它不产生任何新的功能,为什么他们提到它作为一个功能? 我对这个概念的理解有缺陷吗?

The diamond operator in java 7 allows code like the following:

List<String> list = new LinkedList<>();

However in Java 5/6, I can simply write:

List<String> list = new LinkedList();

My understanding of type erasure is that these are exactly the same. (The generic gets removed at runtime anyway).

Why bother with the diamond at all? What new functionality / type safety does it allow? If it doesn't yield any new functionality why do they mention it as a feature? Is my understanding of this concept flawed?

最满意答案

的问题

List<String> list = new LinkedList();

是在左边,你使用通用类型List<String> ,在右边你使用原始类型LinkedList 。 Java中的原始类型有效地仅存在于与泛型代码的兼容性,除非您绝对必须使用,否则不应在新代码中使用。

现在,如果Java从一开始就有泛型,并没有类似于LinkedList这样的类型,例如最初在泛型之前创建的,那么它可能已经使得它使得通用类型的构造函数自动地将它的类型参数从如果可能,作业的左侧。 但是它没有,它必须以不同的方式对待原始类型和通用类型以实现向后兼容。 这使得他们需要做出稍微不同但同样方便的方式来声明一个通用对象的新实例,而不必重复其类型参数...钻石操作符。

就您的List<String> list = new LinkedList()的原始示例而言,编译器会为该分配生成一个警告,因为它必须。 考虑这个:

List<String> strings = ... // some list that contains some strings // Totally legal since you used the raw type and lost all type checking! List<Integer> integers = new LinkedList(strings);

存在泛型以提供编译时保护而不做错事。 在上面的例子中,使用原始类型意味着你没有得到这个保护,并将在运行时收到错误。 这就是为什么你不应该使用原始类型。

// Not legal since the right side is actually generic! List<Integer> integers = new LinkedList<>(strings);

然而,钻石操作员允许将作业的右侧定义为具有与左侧相同类型参数的真实通用实例,而无需再次键入这些参数。 它允许您保持泛型的安全性与使用原始类型几乎相同的努力。

我认为要了解的关键是,原始类型(没有<> )不能被视为与通用类型相同。 当你声明一个原始类型时,你不会得到泛型的好处和类型检查。 您还必须记住, 泛型是Java语言的通用部分,它们不仅适用于Collection的无参考构造函数!

The issue with

List<String> list = new LinkedList();

is that on the left hand side, you are using the generic type List<String> where on the right side you are using the raw type LinkedList. Raw types in Java effectively only exist for compatibility with pre-generics code and should never be used in new code unless you absolutely have to.

Now, if Java had generics from the beginning and didn't have types, such as LinkedList, that were originally created before it had generics, it probably could have made it so that the constructor for a generic type automatically infers its type parameters from the left-hand side of the assignment if possible. But it didn't, and it must treat raw types and generic types differently for backwards compatibility. That leaves them needing to make a slightly different, but equally convenient, way of declaring a new instance of a generic object without having to repeat its type parameters... the diamond operator.

As far as your original example of List<String> list = new LinkedList(), the compiler generates a warning for that assignment because it must. Consider this:

List<String> strings = ... // some list that contains some strings // Totally legal since you used the raw type and lost all type checking! List<Integer> integers = new LinkedList(strings);

Generics exist to provide compile-time protection against doing the wrong thing. In the above example, using the raw type means you don't get this protection and will get an error at runtime. This is why you should not use raw types.

// Not legal since the right side is actually generic! List<Integer> integers = new LinkedList<>(strings);

The diamond operator, however, allows the right hand side of the assignment to be defined as a true generic instance with the same type parameters as the left side... without having to type those parameters again. It allows you to keep the safety of generics with almost the same effort as using the raw type.

I think the key thing to understand is that raw types (with no <>) cannot be treated the same as generic types. When you declare a raw type, you get none of the benefits and type checking of generics. You also have to keep in mind that generics are a general purpose part of the Java language... they don't just apply to the no-arg constructors of Collections!

Java 7中钻石操作员的要点是什么?(What is the point of the diamond operator (<>) in Java 7?)

java 7中的钻石操作符允许代码如下:

List<String> list = new LinkedList<>();

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

List<String> list = new LinkedList();

我对类型擦除的理解是这些完全一样。 (一般在运行时被删除)。

为什么要打钻石呢? 它允许什么新的功能/类型的安全? 如果它不产生任何新的功能,为什么他们提到它作为一个功能? 我对这个概念的理解有缺陷吗?

The diamond operator in java 7 allows code like the following:

List<String> list = new LinkedList<>();

However in Java 5/6, I can simply write:

List<String> list = new LinkedList();

My understanding of type erasure is that these are exactly the same. (The generic gets removed at runtime anyway).

Why bother with the diamond at all? What new functionality / type safety does it allow? If it doesn't yield any new functionality why do they mention it as a feature? Is my understanding of this concept flawed?

最满意答案

的问题

List<String> list = new LinkedList();

是在左边,你使用通用类型List<String> ,在右边你使用原始类型LinkedList 。 Java中的原始类型有效地仅存在于与泛型代码的兼容性,除非您绝对必须使用,否则不应在新代码中使用。

现在,如果Java从一开始就有泛型,并没有类似于LinkedList这样的类型,例如最初在泛型之前创建的,那么它可能已经使得它使得通用类型的构造函数自动地将它的类型参数从如果可能,作业的左侧。 但是它没有,它必须以不同的方式对待原始类型和通用类型以实现向后兼容。 这使得他们需要做出稍微不同但同样方便的方式来声明一个通用对象的新实例,而不必重复其类型参数...钻石操作符。

就您的List<String> list = new LinkedList()的原始示例而言,编译器会为该分配生成一个警告,因为它必须。 考虑这个:

List<String> strings = ... // some list that contains some strings // Totally legal since you used the raw type and lost all type checking! List<Integer> integers = new LinkedList(strings);

存在泛型以提供编译时保护而不做错事。 在上面的例子中,使用原始类型意味着你没有得到这个保护,并将在运行时收到错误。 这就是为什么你不应该使用原始类型。

// Not legal since the right side is actually generic! List<Integer> integers = new LinkedList<>(strings);

然而,钻石操作员允许将作业的右侧定义为具有与左侧相同类型参数的真实通用实例,而无需再次键入这些参数。 它允许您保持泛型的安全性与使用原始类型几乎相同的努力。

我认为要了解的关键是,原始类型(没有<> )不能被视为与通用类型相同。 当你声明一个原始类型时,你不会得到泛型的好处和类型检查。 您还必须记住, 泛型是Java语言的通用部分,它们不仅适用于Collection的无参考构造函数!

The issue with

List<String> list = new LinkedList();

is that on the left hand side, you are using the generic type List<String> where on the right side you are using the raw type LinkedList. Raw types in Java effectively only exist for compatibility with pre-generics code and should never be used in new code unless you absolutely have to.

Now, if Java had generics from the beginning and didn't have types, such as LinkedList, that were originally created before it had generics, it probably could have made it so that the constructor for a generic type automatically infers its type parameters from the left-hand side of the assignment if possible. But it didn't, and it must treat raw types and generic types differently for backwards compatibility. That leaves them needing to make a slightly different, but equally convenient, way of declaring a new instance of a generic object without having to repeat its type parameters... the diamond operator.

As far as your original example of List<String> list = new LinkedList(), the compiler generates a warning for that assignment because it must. Consider this:

List<String> strings = ... // some list that contains some strings // Totally legal since you used the raw type and lost all type checking! List<Integer> integers = new LinkedList(strings);

Generics exist to provide compile-time protection against doing the wrong thing. In the above example, using the raw type means you don't get this protection and will get an error at runtime. This is why you should not use raw types.

// Not legal since the right side is actually generic! List<Integer> integers = new LinkedList<>(strings);

The diamond operator, however, allows the right hand side of the assignment to be defined as a true generic instance with the same type parameters as the left side... without having to type those parameters again. It allows you to keep the safety of generics with almost the same effort as using the raw type.

I think the key thing to understand is that raw types (with no <>) cannot be treated the same as generic types. When you declare a raw type, you get none of the benefits and type checking of generics. You also have to keep in mind that generics are a general purpose part of the Java language... they don't just apply to the no-arg constructors of Collections!