【问题标题】:Java unsafe or unchecked expressions: cloning an arraylistJava 不安全或未经检查的表达式:克隆数组列表
【发布时间】:2012-02-12 20:57:09
【问题描述】:

编译时出现unchecked expression错误,发现有问题的行是

ArrayList<Integer> items = (ArrayList<Integer>) this.items.clone();

我正在尝试执行我的对象的深层复制,因此我正在以上述方式克隆对象和数组列表的属性。如何解决此警告?

  • 我可以使用@SuppressWarnings("unchecked"),但这只是隐藏了问题(我希望没有)
  • 如果我通过循环遍历所有元素来手动克隆,我认为会更慢

这样做的正确方法是什么?

【问题讨论】:

    标签: java compiler-errors type-safety


    【解决方案1】:

    您可以使用new ArrayList&lt;Integer&gt;(this.items) 获得相同的行为。不过,无论哪种方式,它都是副本。

    API

    【讨论】:

    • 当然,没有必要对Integer对象进行深拷贝。
    【解决方案2】:

    由于在将泛型引入 Java API 时需要向后兼容,因此在某些情况下无法使用强制转换和 @SuppressWarnings("unchecked")

    另外,请参阅here,了解为什么要谨慎使用 clone() 的原因:它会进行浅拷贝,这对基元很好,但对对象很危险。

    【讨论】:

    • 您可以将原语放在ArrayListss 中吗?我以为你只能放置对象,充其量是原语的包装器。
    • @blahman 关键是克隆时原始字段很好,但对象字段(如ArrayList&lt;Integer&gt; items)是麻烦的根源。
    • 哦...哎呀。完全错过了。对不起,佑希。我的坏^^'另外,谢谢@TedHopp =)
    【解决方案3】:

    您说过您正在尝试进行深层复制,但正如 here 所讨论的那样,我怀疑您是否能够使用 clone() 做到这一点。因此,就像其他发帖人所说的那样,使用clone() 是一种更危险的方法,您将无法获得您一直在寻找的深层副本。

    【讨论】:

      【解决方案4】:

      如果您的元素是整数,那么执行“深度复制”确实不是问题,因为您没有理由需要复制整数对象。只需使用new ArrayList&lt;Integer&gt;(this.items)

      但作为参考,clone() 和 ArrayList 复制构造函数都不会进行深度复制。只是因为您的元素类型不需要深度复制才能满足您的需求。

      【讨论】:

        【解决方案5】:

        整数是不可变的,因此是否进行深层复制并不重要。

        使用 java.util 中的 Collections 实用程序类:

        import java.util.Collections;
        ...
        ArrayList<Integer> items = new ArrayList<Integer>(this.items.size());
        Collections.copy(items, this.items);
        

        【讨论】:

        • Arrays.copyOf 不返回 ArrayList
        • 糟糕,是指 Collections.copy,而不是 Arrays.copyOf。
        【解决方案6】:

        正如其他人指出的那样,克隆 ArrayList 不会克隆其元素。如果您想制作内容的深层副本,有一个巧妙的技巧:序列化和反序列化数组。 (这是因为ArrayListInteger 都实现了Serializable。)但是,这并不能消除抑制未经检查的转换警告的需要。

        // Write the object out to a byte array
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(this.items);
        byte[] bytes = bos.toByteArray();
        
        // Retrieve an input stream from the byte array and read
        // a copy of the object back in.
        ObjectInputStream in = new ObjectInputStream(
            new ByteArrayInputStream(bytes));
        ArrayList<Integer> items = (ArrayList<Integer>) in.readObject();
        

        如果您的整个对象都可以声明为可序列化,您可以使用它而不是克隆操作来制作您的深层副本。另外,请参阅this article 以了解避免从ByteArrayOutputStream 复制字节的费用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-07-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多