Java 在ArrayList上指定类型参数的位置

Java 在ArrayList上指定类型参数的位置,java,generics,Java,Generics,两侧铸造的区别是什么: List <String>myNumbers = new ArrayList<String>(); List myNumbers=new ArrayList(); 与: List <String>myNumbers = new ArrayList(); List myNumbers=new ArrayList(); 以及: List myNumbers=new ArrayList(); 第一个示例是类型安全,这意味着如果您试图将

两侧铸造的区别是什么:

List <String>myNumbers = new ArrayList<String>();
List myNumbers=new ArrayList();
与:

List <String>myNumbers = new ArrayList();
List myNumbers=new ArrayList();
以及:

List myNumbers=new ArrayList();

第一个示例是类型安全,这意味着如果您试图将
字符串
对象以外的任何内容添加到
myNumbers
列表中,则会出现编译器错误

List <String> myNumbers = new ArrayList<String>();
原始类型 原始类型是泛型类或接口的名称,没有任何 类型参数

在JDK1.5中引入泛型时,原始类型仅为向后兼容较旧版本的java而保留。尽管仍允许使用原始类型,但出于以下原因,您应避免使用原始类型:

  • 通常,原始类型需要强制转换
  • 原始类型不是类型安全的,一些重要类型的错误只会在运行时出现
  • 原始类型的表达能力较差&不要像参数化类型那样自行编制文档
最后一个示例是原始类型,这意味着我们可以将所有类型的对象添加到
myNumbers
列表中,但是,如果可以,您应该避免使用它们

List myNumbers = new ArrayList<String>();
但是,只要编译器可以从上下文推断类型参数,就可以用一组空的类型参数(
)替换调用泛型类构造函数所需的类型参数

意思不是这个:

List <String> myNumbers = new ArrayList<String>();
List myNumbers=new ArrayList();
我们可以这样做:

List <String> myNumbers = new ArrayList<>();
List myNumbers=new ArrayList();

让我们逐一介绍一下

List <String>myNumbers = new ArrayList<String>();
与前面一样,
myNumbers
约束仅存储
String
对象。不同的是,
new ArrayList()
将存储任何对象,它是原始类型。所以这就是编译
newarraylist()
将保存
String
对象,因此它可以编译。在本节中,可以阅读更多关于约束和类型缩减的内容。这属于推理的主题

第18章。类型推断

各种编译时分析都需要对未知的类型进行推理。其中主要包括通用方法适用性测试(§18.5.1)和通用方法调用类型推断(§18.5.2)。通常,我们将未知类型的推理过程称为类型推理

在较高的层次上,类型推断可分解为三个过程:

  • reduce接受关于表达式或类型的兼容性断言(称为约束公式),并将其简化为推理变量的一组边界。通常,一个约束公式简化为其他约束公式,必须递归地简化。遵循一个过程来识别这些额外的约束公式,并最终通过一个绑定集来表示条件,在该条件下,推断类型的选择将使每个约束公式为真
最后是你的第三个例子

List <String>myNumbers = new ArrayList();
List myNumbers = new ArrayList<String>();
List myNumbers=new ArrayList();
这是最有趣的一个,因为它引入了类型擦除和原始类型。本质上发生的是,即使使用参数化的
字符串来实例化
新的ArrayList()
,Java允许忽略这一点以允许原始类型,擦除的概念和规则是如何实现的。至少可以从Java语言规范的第4.8节和第4.6节中推断出这一点

4.8。原始类型

为了便于与非通用遗留代码接口,可以使用参数化类型(§4.5)的擦除(§4.6)或元素类型为参数化类型的数组类型(§10.1)的擦除作为类型。这种类型称为原始类型

此外

4.6。类型擦除

…跳过几个要点

类型擦除还将构造函数或方法的签名(§8.4.2)映射到
没有参数化类型或类型变量的签名。构造函数或方法签名s的擦除是一个签名,由与s相同的名称和s中给出的所有形式参数类型的擦除组成

如果方法或构造函数的签名被删除,则方法的返回类型(§8.4.5)和泛型方法或构造函数的类型参数(§8.4.4,§8.8.4)也会被删除

泛型方法签名的擦除没有类型参数


应该是两边都有。也可以执行
List List=new ArrayList()
如果未指定ArrayList或List的类型,则编译器将通过传递到此ArrayList或List的数据来确定。如果指定它,则必须按照指定的方式准确传递数据类型。我认为标题应该是指定类型参数的位置ArrayList@TuyenNguyen如果未指定类型,则类型为
Object
。编译器甚至不一定能看到您传递给列表的内容,更不用说从中确定类型了。关于第二个示例,请解释:“……但仅当直接将项添加到myNumbers列表中时”。那么,另一种方式是什么呢?我只想通过myNumbers.add(“string here”)添加项目。它的行为就像一个例子,就是,它强制提供字符串。@JohnSmith我指的是,您可以将包含Object类型项的原始类型ArrayList分配给myNumbers列表,但您可以忽略这一点,因为第二个示例与第一个示例的行为方式相同,就像编译器强制您提供String对象一样。很抱歉,我的答案中有一个输入错误,我现在已经更新了。因此,如果第二个示例的行为与第一个类似,那么现在的问题是,为什么我必须像示例1那样在两侧指定字符串类型参数?为什么我只能在实际变量上定义它(示例2)?你能提供一个真实的案例吗
List <String>myNumbers = new ArrayList<String>();
List <String>myNumbers = new ArrayList();
List myNumbers = new ArrayList<String>();