简体   繁体   English

为什么在 Java 泛型右侧的集合类型没有任何影响?

[英]Why in Java generics right hand side type of the collection does not have any effect?

Using Java's Generics features I created a List object and on the left hand side I am using the raw type List where on the right hand side I am using the generic type ArrayList< String >.使用 Java 的泛型特性,我创建了一个 List 对象,在左侧我使用原始类型 List,而在右侧我使用泛型类型 ArrayList<String>。

List myList=new ArrayList<String>();

And I added one int value into the list object.我在列表对象中添加了一个 int 值。

myList.add(101);

I was hoping that I will get some compilation error but this program is running fine.But if I use generic type List< String > on the left hand side and raw type ArrayList on the right hand side and try to add an int value into the list, I am getting compilation error as expected.我希望我会得到一些编译错误,但这个程序运行良好。但是如果我在左侧使用泛型类型 List< String > 并在右侧使用原始类型 ArrayList 并尝试将一个 int 值添加到列表,我按预期收到编译错误。

List<String> myList=new ArrayList();
myList.add(101);//The method add(int, String) in the type List<String> is not applicable for the arguments (int)

Why in Java generics right hand side type of the collection does not have any effect?为什么在 Java 泛型右侧的集合类型没有任何影响? And why Java allowing us to do so when it does not have any effect.I am using Java 1.6.以及为什么 Java 在没有任何影响的情况下允许我们这样做。我使用的是 Java 1.6。 Please explain.请解释。

If you don't supply a generic type parameter on the left-hand side, the List is declared as a raw type.如果您不在左侧提供泛型类型参数,则List被声明为原始类型。 This means the compiler doesn't know what is legal or not to store in that list, and is relying on the programmer to perform appropriate instanceof checks and casts.这意味着编译器不知道在该列表中存储什么是合法的或不合法的,而是依赖程序员执行适当的instanceof检查和强制转换。

Raw types also have the effect of obliterating all generic type information in the class they appear in.原始类型还具有消除它们出现的类中的所有泛型类型信息的效果。

The JLS provides a much more detailed look at raw types. JLS 提供了对原始类型的更详细的了解。 You should be seeing a warning in your IDE or from the compiler about the assignment to a raw type as well:您应该会在 IDE 或编译器中看到有关分配给原始类型的警告:

To make sure that potential violations of the typing rules are always flagged, some accesses to members of a raw type will result in compile-time unchecked warnings.为确保始终标记可能违反类型规则的行为,对原始类型成员的某些访问将导致编译时未经检查的警告。 The rules for compile-time unchecked warnings when accessing members or constructors of raw types are as follows:访问原始类型的成员或构造函数时编译时未检查警告的规则如下:

At an assignment to a field: if the type of the left-hand operand is a raw type, then a compile-time unchecked warning occurs if erasure changes the field's type.在对字段赋值时:如果左侧操作数的类型是原始类型,那么如果擦除更改了字段的类型,则会出现编译时未检查警告。

At an invocation of a method or constructor: if the type of the class or interface to search (§15.12.1) is a raw type, then a compile-time unchecked warning occurs if erasure changes any of the formal parameter types of the method or constructor.在调用方法或构造函数时:如果要搜索的类或接口的类型(第 15.12.1 节)是原始类型,则如果擦除更改了方法的任何形式参数类型,则会出现编译时未经检查的警告或构造函数。

No compile-time unchecked warning occurs for a method call when the formal parameter types do not change under erasure (even if the result type and/or throws clause changes), for reading from a field, or for a class instance creation of a raw type.当形式参数类型在擦除时未更改(即使结果类型和/或 throws 子句更改)、从字段读取或创建原始类实例时,方法调用不会发生编译时未经检查的警告类型。

Tom G's answer is nice and explains things in detail, but I get the feeling that you already know at least some of that stuff, because you said this: Tom G 的回答很好,详细解释了一些事情,但我觉得您至少已经知道其中的一些内容,因为您这样说:

I was hoping that I will get some compilation error我希望我会得到一些编译错误

So, let me address precisely that part.所以,让我准确地谈谈那部分。

The reason you are not getting any compilation error is because generics were added as an afterthought in java, and for this reason many generics-related issues which ought to be errors have instead been demoted to warnings in order to not break existing code.您没有收到任何编译错误的原因是因为在 Java 中添加了泛型作为事后的想法,因此,许多与泛型相关的问题本应是错误,而是降级为警告,以免破坏现有代码。

And what is most probably happening is that these warnings are turned off in your development environment.最有可能发生的是这些警告在您的开发环境中被关闭。

Steps to correct the problem:纠正问题的步骤:

  1. Go to the options of your IDE转到 IDE 的选项

  2. Find the "warnings" section.找到“警告”部分。

  3. Enable EVERYTHING .启用一切

  4. Pick your jaw from the floor after you have seen the enormous number of warnings you get.在您看到收到的大量警告后,请从地板上捡起您的下巴。

  5. Disable all the warnings that do not make any sense, like "hard-coded string" or "member access was not qualified with this ", keep everything else.禁用所有没有任何意义的警告,例如“硬编码字符串”或“成员访问权限不符合this ”,保留其他所有内容。 Be sure that the one which says something like "Raw use of parameterized class" is among the ones you keep.确保说“参数化类的原始使用”之类的内容是您保留的内容之一。

At a glance it looks like myList can only store String乍一看好像myList只能存储String

At a glance, perhaps.乍一看,也许。 But it's really important to realize that there is no such thing as "a list that can only store Strings", at least in the standard APIs.但是意识到没有“只能存储字符串的列表”这样的东西真的很重要,至少在标准 API 中是这样。

There is only List , and you have to include the right instructions to the compiler to berate you if you try to add something that's not a String to it, ie by declaring it as List<String> myList .只有List ,如果您尝试向其中添加不是String的内容(即通过将其声明为List<String> myList ,则必须向编译器包含正确的指令以List<String> myList

If you declare it as "plain old List ", the compiler has no instructions as to what to allow or disallow you to put into it, so you can store anything within the type bounds of the backing array, namely, any Object .如果您将其声明为“plain old List ”,则编译器没有关于允许或禁止您放入其中的内容的说明,因此您可以在支持数组的类型范围内存储任何内容,即任何Object

The fact that you say new ArrayList<String>() on the RHS of the assignment is irrelevant: Java doesn't attempt to track the value assigned to a variable.您在赋值的 RHS 上说new ArrayList<String>()是无关紧要的:Java 不会尝试跟踪分配给变量的值。 The type of a variable is the type you declare.变量的类型是您声明的类型。

"... generics right hand side of type of the collection does not have any effect" is mostly true. “...泛型右侧的集合类型没有任何影响”大部分是正确的。 When the "var" keyword is substituted for "List", the right hand side generic does have an effect.当“var”关键字替换“List”时,右侧泛型确实有效果。 The code below creates an ArrayList of Strings.下面的代码创建了一个字符串的 ArrayList。

var myList = new ArrayList<String>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Java 6中使用Generics在右侧? - Using Generics on right hand side in Java 6? 为什么在 Java 的类型转换期间允许在右侧使用(已擦除)泛型类型? - Why is usage of the (erased) generic type in right-hand side allowed during type casting in Java? Java的逻辑OR运算符不评估右侧,尽管右侧具有一元运算符? - Java's logical OR operator does not evaluate right hand side despite that right hand side has a unary operator? 为什么在Java 7中右手边没有漏掉Diamond运算符? - Why Diamond operator was not missed from Right hand side in Java 7? 为什么Java泛型必须擦除类型信息? - why java generics have to erase the type information? 为什么 Java 在 generics 中有下限? - Why does Java have lower bounds in generics? 任何类型的 Java 泛型<?> - Java Generics With Any Type <?> Hibernate多对多关联:左侧收集包含元素,但右侧收集是空的 - Hibernate Many-to-many association: left hand side collection contains elements, but right hand side collection is empty System.out.println()在Java中是否有副作用? - Does System.out.println() have a side effect in Java? Java:创建对象时,为什么接口不在右侧? - Java: When creating an object, why isn't the interface on the right hand side?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM