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

为什么在Java泛型中,集合的右侧类型并没有任何影响?,java,generics,collections,java-6,Java,Generics,Collections,Java 6,使用Java的泛型特性,我创建了一个列表对象,在左侧我使用原始类型列表,在右侧我使用泛型类型ArrayList List myList=new ArrayList<String>(); 我希望我会得到一些编译错误,但是这个程序运行得很好。但是如果我在左侧使用泛型类型List,在右侧使用原始类型ArrayList,并尝试在列表中添加一个int值,我会得到预期的编译错误 List<String> myList=new ArrayList(); myList.add(101)

使用Java的泛型特性,我创建了一个列表对象,在左侧我使用原始类型列表,在右侧我使用泛型类型ArrayList

List myList=new ArrayList<String>();
我希望我会得到一些编译错误,但是这个程序运行得很好。但是如果我在左侧使用泛型类型List,在右侧使用原始类型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)
List myList=new ArrayList();
myList.add(101)//类型列表中的add(int,String)方法不适用于参数(int)

为什么在Java泛型中,集合的右侧类型并没有任何影响?为什么Java允许我们在没有任何效果的情况下这样做呢?我使用的是Java1.6。请解释。

如果您没有在左侧提供泛型类型参数,
列表将声明为原始类型。这意味着编译器不知道在该列表中存储什么是合法的或不合法的,并且依赖程序员执行适当的
instanceof
检查和强制转换

原始类型还具有删除类中出现的所有泛型类型信息的效果

JLS提供了一个警告,您应该会在IDE或编译器中看到有关分配给原始类型的警告:

确保始终存在可能违反键入规则的情况 标记后,对原始类型成员的某些访问将导致 编译时未检查的警告。未选中编译时规则 访问原始类型的成员或构造函数时的警告如下 如下:

在字段赋值时:如果左侧操作数的类型为 原始类型,则在删除时会出现编译时未检查警告 更改字段的类型

在调用方法或构造函数时:如果类的类型 或搜索接口(§15.12.1)是原始类型,然后是编译时 如果擦除更改了任何形式的 方法或构造函数的参数类型

当 形式参数类型在擦除时不会改变(即使结果 类型和/或抛出子句更改),用于从字段读取,或用于 类创建原始类型的实例


Tom G的回答很好,解释得很详细,但我觉得你至少已经知道了一些东西,因为你说过:

我希望我会得到一些编译错误

所以,让我来具体说明这一部分

您没有收到任何编译错误的原因是,泛型是在java中作为事后考虑添加的,因此,许多与泛型相关的问题(应该是错误)已降级为警告,以避免破坏现有代码

最可能发生的是,这些警告在您的开发环境中被关闭

纠正问题的步骤:

  • 转到IDE的选项

  • 查找“警告”部分

  • 启用所有功能

  • 当你看到这个庞大的数字后,从地板上抬起你的下巴 你会收到很多警告

  • 禁用所有没有任何意义的警告,如“硬编码字符串”或“成员访问不符合<代码>此”等,保留所有其他内容。请确保您保留的内容中包含“参数化类的原始使用”之类的内容

  • “…泛型集合类型的右侧并没有任何效果”基本上是正确的。当“var”关键字替换为“List”时,右侧的generic确实会起作用。下面的代码创建字符串的ArrayList

    var myList = new ArrayList<String>();
    
    var myList=new ArrayList();
    
    乍一看,myList似乎只能存储字符串

    也许是一瞥吧。但认识到“只能存储字符串的列表”是不存在的,至少在标准API中是不存在的,这一点非常重要

    只有
    列表
    ,如果您试图向其中添加非
    字符串
    的内容,即将其声明为
    列表
    ,则必须向编译器提供正确的指令,以严厉批评您

    如果您将其声明为“纯旧
    列表
    ”,编译器没有关于允许或不允许您将什么放入其中的指令,因此您可以存储支持数组的类型边界内的任何内容,即任何
    对象


    您在赋值的RHS上说
    new ArrayList()
    ,这一事实与此无关:Java不会尝试跟踪分配给变量的值。变量的类型就是您声明的类型。

    请阅读可能重复的内容,谢谢您的回复,但我主要关心的是我正在声明List myList=new ArrayList();乍一看,myList似乎只能存储字符串,因为我在右侧提到了类型字符串。但是myList可以存储任何类型的对象。为什么Java允许我们在右边提到类型?这不令人困惑吗?也许,这就是他们在Java7中引入菱形操作符的原因。我的帖子缺少了泛型。它应该是:var myList=new ArrayList();
    var myList = new ArrayList<String>();