【问题标题】:How do I make a deep copy of an ArrayList<Integer> in Java? [duplicate]如何在 Java 中制作 ArrayList<Integer> 的深层副本? [复制]
【发布时间】:2017-06-23 08:29:06
【问题描述】:

我基本上只是想对 1 和 0 进行深度复制,所以我可以使用布尔值,但我想知道如何在一般情况下为整数执行此操作。

private ArrayList<Integer> makeDeepCopyInteger(ArrayList<Integer> a) {
    ArrayList<Integer> newA = new ArrayList<>(a.size());
    for (int i = 0; i < a.size(); i++) {
        int newInt = 0;
        if (a.get(i) == 1) {
            newInt = 1;
        }
        newA.add(newInt);
    }
    return newA;
}

【问题讨论】:

  • 既然整数是不可变的,为什么要深拷贝它们?

标签: java arraylist deep-copy


【解决方案1】:

clone() 方法受Integer 类的保护,因此您不能在该类之外调用Integer.clone()。您可以做的是创建一个 new 整数。

private ArrayList<Integer> makeDeepCopyInteger(ArrayList<Integer> old){
    ArrayList<Integer> copy = new ArrayList<Integer>(old.size());
    for(Integer i : old){
        copy.add(new Integer(i));
    }
    return copy;
}

您可以通过执行以下操作来测试它是否有效:

public static void main (String[] args) throws java.lang.Exception
{
    ArrayList<Integer> arr = new ArrayList<>();
    for(int i = 0; i<5; i++){
        arr.add(new Integer(i));
    }
    ArrayList<Integer> x = makeDeepCopyInteger(arr);
    for(int i = 0; i<x.size(); i++){
        if(arr.get(i) == x.get(i)){
            System.out.println("Same object");
        } else {
            System.out.println("Not the same object");
        }
    }
}

测试

Integer a = new Integer(1);
Integer b = new Integer(a);

System.out.println(a==b); // true
System.out.println(System.identityHashCode(a) == (System.identityHashCode(b))); // false;


Integer a = new Integer(1);
Integer b = a;

System.out.println(a==b); // true
System.out.println(System.identityHashCode(a) == (System.identityHashCode(b))); // true

所以从我的测试看来,要创建一个用于复制到新数组的新引用,您应该使用new Integer()Integer 是一个不可变对象,但当 Integer 的值发生变化时,该引用也会发生变化。

【讨论】:

  • 由于Integer 是不可变的,您不需要创建它的副本。
  • @Kayaman 我对此进行了一些测试,请参阅我的编辑。也许我很困惑,但由于不创建副本,它似乎保留了旧的参考。
  • 这没有什么问题。由于Integer 的值不能改变,例如,如果您有1000 个列表都引用相同的17 并不重要。你的最后一段是错误的。由于Integer 是不可变的,所以它的值不能改变。
【解决方案2】:

使用流来复制对象。易于阅读,适合 JIT。以下代码提供了一个列表副本,其中包含 Integer 对象副本。

private ArrayList<Integer> makeDeepCopyInteger(ArrayList<Integer> a){
    return a.stream().map(val -> new Integer(val)).collect(toList());
}

复制除整数以外的自定义对象覆盖实现并调用clone()

return a.stream().map(MyObjectClass::clone).collect(toList());

您可以使用序列化到 json 来代替克隆。例如。在 BeanUtils.getCopy(sourceBean) 中使用 java-utils

【讨论】:

  • 欢迎来到堆栈溢出 :-) 请看How to Answer。您应该提供一些信息为什么您的代码可以解决问题。仅代码答案对社区没有用处。
【解决方案3】:

可以执行以下操作:

public static List<Integer> clone(List<Integer> source) {
   return source.stream()
       .map( intObj -> new Integer(intObj.intValue()))
       .collect(Collectors.toList());
}

或者,更老式的:

public static List<Integer> clone(List<Integer> source) {
   List<Integer> newList = new ArrayList<>();
   for(Integer intObj : source) {
      newList.add(new Integer(intObj.intValue()));
   }
   return newList;
}

通过利用自动装箱/自动拆箱,可以缩短这两者。但我已经明确表示要绝对清楚发生了什么。

但是,这是一种毫无意义的练习 - 事实上,它会浪费内存并且不利于性能。 Integer 是不可变的,因此更好的引用指向Integer 的同一实例。因为Integer不可能改变值,所以不可能通过共享实例造成任何伤害。

这适用于一般的不可变对象,这也是它们是好东西的原因。

作为初学者,您不太可能找到new Integer(...) 是一个好主意的情况(甚至Integer.valueOf(int i),尽管这可能会返回一个缓存实例)。如果您已经有Integer,请使用您拥有的:

 Integer oldVar = ... ;
 Integer newVar = oldVar;

不变性意味着永远没问题。对newVar 的操作不可能破坏oldVar,因为没有newVar.setValue(newValue)

如果您有int,请直接使用它并允许Java 的自动装箱将其转换为Integer

 int oldValue = ... ;
 Integer newValue = oldValue ; // Java will automatically put this through
                               // Integer.valueOf(int i)

您提到您真的很想使用布尔值。您应该考虑使用BitSet

【讨论】:

    【解决方案4】:

    您必须遍历列表中的项目并在之前克隆它们,然后将它们添加到新列表中,如下所述:

    How to clone ArrayList and also clone its contents?

    【讨论】:

      猜你喜欢
      • 2011-10-25
      • 1970-01-01
      • 2011-05-03
      • 1970-01-01
      • 2013-06-30
      • 2015-12-28
      相关资源
      最近更新 更多