【问题标题】:ArrayList Generic without Type无类型的 ArrayList 泛型
【发布时间】:2014-09-05 15:50:56
【问题描述】:

最近我读了一段对我来说很奇怪的代码。众所周知,当我们需要使用集合时,我们需要初始化集合中的泛型类型。此外,我们知道集合可以包含集合作为它们的元素。

代码:

public class Solution {
public static void main(String args[]) {
    ArrayList res = returnlist();
    System.out.print(res.get(0));
}
public static ArrayList<ArrayList<Integer>> returnlist() {
    ArrayList result = new ArrayList();
    ArrayList<Integer> content = new ArrayList<Integer>();
    content.add(1);
    result.add(content);
    return result;
}}

我的问题是

  • 为什么我们可以使用ArrayList result = new ArrayList(); 来创建一个对象,因为我们没有为集合提供元素的实际类型。
  • 为什么我们可以使用result.add(content); 将集合添加到集合中,集合“结果”只是一个普通集合。我们尚未将其定义为 ArrayListArrayList

【问题讨论】:

    标签: java generics arraylist


    【解决方案1】:

    Java 泛型集合不与类型一起存储,以确保向后兼容 J2SE 5.0 之前的版本。类型信息在添加到泛型集合时会被删除。这称为Type Erasure

    这意味着可以将泛型集合分配给非泛型引用,并且可以将泛型类型化集合中的对象放置在非泛型、非类型化集合中。

    所有 Java 泛型真正做的是确保您不能将错误的类型添加到泛型列表中,并避免您在检索时执行 explicit 强制转换;即使它仍然完成implicitly

    更进一步

    【讨论】:

    • 是我声望不够给你打分。哈哈
    【解决方案2】:

    只是加起来提供总结的答案

    老办法:

    (A) ArrayList result = new ArrayList();
    

    将创建一个 Arraylist 来保存“对象”


    新方法:

    ArrayList<Integer> content = new ArrayList<Integer>();
    

    this 表示一个 Arraylist,它将保存“Integer”对象。这是为了编译时类型检查而引入的。


    为什么?

    考虑第一种情况。它的输入类型是Object。我们知道 Object 是所有类的超类。我们可以传入一个 Integer 对象、String 对象等等。在获取数据时,开发人员必须执行正确的类型转换。假设开发人员最初认为代码将接受 Integer 对象,因此他在获取数据时添加了以下类型转换

    Integer integer=(Integer) content.get(0);
    

    这应该有效。但是如果他错误地传递了一个字符串,它将导致运行时错误。

    如何避免?

    通过引入编译时检查


    它是如何工作的?

    当我们指定参数化类型时,只能将 Integer 对象添加到 ArrayList 集合中。否则会报错。

    content.add(3); // will work
    content.add("HARSHAD"); // error shown
    

    如果参数化泛型类型用于类型检查,如何从列表中检索正确的数据?

    编译器隐式执行类型转换。查看示例代码

    List<Integer> list=new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    Integer integer=list.get(0);
    System.out.println(integer);
    

    编译器在执行编译时实际上做了什么?

    //perform type erasure
    (B) List list=new ArrayList();
        list.add(1);
        list.add(2);
    
    // the arraylist inturn accepts Object when you run the code 
    
    //add casting 
    Integer integer=(Integer)list.get(0);
    

    结论

    如果您看到代码 (A) 和 (B) 两者是相同的。唯一不同的是,在第二种情况下,编译器会隐式执行相同的操作。

    终于回答你的问题了……

    ArrayList result = new ArrayList();
    

    允许用于向后兼容的目的。虽然不推荐这样做。

    来自Oracle docs 的官方链接解释了相同的概念。

    【讨论】:

      【解决方案3】:

      泛型仅在 Java 5 中添加到 Java。在此之前,当您使用集合时,它总是意味着对象的集合。为了向后兼容,保留旧语法。所以ArrayList result = new ArrayList() 实际上是在创建一个ArrayList&lt;Object&gt;。由于 ArrayList 也是一个对象,所以可以将content 添加到变量result 中。

      【讨论】:

      • 有道理。但是在日常编程中使用没有泛型的集合仍然是一种流行的方式吗?
      • 不推荐用于新代码。但是有很多代码是在 Java 5 之前编写的,在维护这些代码甚至扩展它时,人们倾向于使用旧样式。
      【解决方案4】:

      为什么我们可以使用ArrayList result = new ArrayList();来创建一个对象,因为我们没有给集合元素的实际类型。

      因为java希望它向后兼容。泛型更多的是用于确保类型安全的编译器功能,集合可以在运行时存储任何类型的对象。

      Java 编译器不会为此给您编译器错误,但它一定给您编译器警告,使用没有类型的泛型类是不安全的。

      【讨论】:

        【解决方案5】:

        这可能是泛型出现在 java 之前的遗留物(我认为是 Java 4 或 5)。

        【讨论】:

        • 不一定是remnant,但绝对是不使用泛型的特性。您必须将这些项目投射到结果上才能在获得它们时使用它们。
        • 是的。看来我们需要在没有泛型的情况下处理我们存储在 ArrayList 中的东西。
        猜你喜欢
        • 1970-01-01
        • 2021-07-16
        • 1970-01-01
        • 2014-06-12
        • 2014-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-30
        相关资源
        最近更新 更多