【问题标题】:Deep copy of a list with custom objects in javajava中带有自定义对象的列表的深层副本
【发布时间】:2018-07-12 12:42:21
【问题描述】:

我有一个包含自定义对象的列表。我想创建该列表的深层副本。 这是自定义对象的类:

public class MyMemo {
    private List<Uri> imageUriList;
    private String commentText;

    public MyMemo(){
        imageUriList = new ArrayList<>();
    }

    public List<Uri> getImageUriList() {
        return imageUriList;
    }

    public void setImageUriList(List<Uri> imageUriList) {
        this.imageUriList = imageUriList;
    }

    public String getCommentText() {
        return commentText;
    }

    public void setCommentText(String commentText) {
        this.commentText = commentText;
    }
}

现在我有以下情况:

List<MyMemo> parentList = new ArrayList<>();
List<MyMemo> copyList = new ArrayList<>(parentList);
parentList.get(currentMemoPosition).getImageUriList().removeAll(someOtherList.getImageUriList());
Log.e(TAG,"Total List: "+parentList.get(currentMemoPosition).getImageUriList().size()+" "+copyList.get(currentMemoPosition).getImageUriList().size());

但是,如果我对 parentList 进行任何更改,即 delete 中的一个项目或 add 新项目。 copyList 也会生效。如何确保 copyList 没有引用相同的内存地址。

更新:

建议使用clone()。但问题是我的自定义对象中有一个列表。我怎样才能clone()他们?

【问题讨论】:

  • 创建一个clone 方法,它将source 的每个元素复制到应作为返回值的destination 中。有点像 Prototype 设计模式。
  • 你能举一个例子main()方法来说明你遇到的问题吗?
  • @Code-Apprentice 更新了我的代码。我使用removeAll() 来更改parentList 的自定义对象的内部列表。但这也会影响copyList 的大小。
  • @Ravi 我在每个自定义对象中都有一个列表。如何克隆它们?

标签: java android


【解决方案1】:

IMO,添加另一个 arg 构造函数,它将为您的对象进行深度克隆。

public class MyMemo {
    MyMemo(MyMemo memo)
    {
       this.commentText = memo.getCommentText();
       this.imageUriList = new ArrayList<>();
       for (Uri uri : memo. getImageUriList())
       {
           this.imageUriList.add(new Uri(uri));
       }
    }
    // rest of your code
}

现在,迭代你的父列表并克隆每个对象

List<MyMemo> parentList = new ArrayList<>();
List<MyMemo> copyList = new ArrayList<>();
for (MyMemo memo : parentList)
{
   // create new instance of MyMemo and add to the list
   copyList.add(new MyMemo(memo));
}

【讨论】:

  • 像魅力一样工作:)
【解决方案2】:

当您创建第一个列表时:

List<MyMemo> parentList = new ArrayList<>();
parentList.add(customObject1);
parentList.add(customObject2);
parentList.add(customObject3);

parentList 是自定义对象的引用列表。

当你将parentList的内容复制到copyList中时:

List<MyMemo> copyList = new ArrayList<>(parentList);

copyList 现在包含对与parentList 相同的对象的引用。如果您更改parentList 中的对象,则copyList 中的对象也会更改,因为它们是同一个对象。

要创建列表的深层副本,您需要一种复制自定义对象的方法。您可以实现复制构造函数或克隆方法:

class CustomObject {
    private String item1;
    private String item2;

    public CustomObject(String item1, String item2) {
        this.item1 = item1;
        this.item2 = item2;
    }

    // copy constructor
    public CustomObject(CustomObject other) {
        this.item1 = other.getItem1();
        this.item2 = other.getItem2();
    }

    // clone
    public CustomObject clone() {
        CustomObject newObj = new CustomObject(this.getItem1(), this.getItem2());
        return newObj;
    }
}

然后你可以像这样复制一个对象:

CustomObject newObj = new CustomObject(existingObj);

或者像这样:

CustomObject newObj = existingObj.clone();

现在您可以使用复制构造函数对列表进行深层复制:

List<CustomObject> copyList = new ArrayList<>();
for(CustomObject obj : parentList) {
    copyList.add(new CustomObject(obj));
}

或克隆方法:

List<CustomObject> copyList = new ArrayList<>();
for(CustomObject obj : parentList) {
    copyList.add(obj.clone());
}

我更喜欢使用复制构造函数。你可以阅读good article by Josh Block in Effective Java 了解克隆与复制构造函数的使用。

【讨论】:

  • 惊人的解释。
【解决方案3】:

下面的所有选项都会生成一个浅拷贝,这意味着更改一个数组中的值会影响第二个数组。它不是线程安全的

1.

         List<Sth> a = new ArrayList<>();
         List<Sth> b = new ArrayList<>(a);

2.

        `Collection.copy(a,b)`

3.

ArrayList<Sth> b= (ArrayList) a.clone();

要创建一个新副本,如果您应该在此列表上迭代并将元素添加到另一个列表中。这是一个深拷贝

【讨论】:

    【解决方案4】:

    您还可以创建新列表,创建新对象并使用 BeanUtils 复制属性,

    for (MyMemo current : parentList) {
        MyMemo copyCurrent = new Data();
        BeanUtils.copyProperties(copyCurrent, current);
        copyList.add(copyCurrent);
    }
    

    这将提供列表中对象的深层副本。

    【讨论】:

      【解决方案5】:

      在 Android 中,如果您尝试将对象类型为 ArrayList 进行深度复制,那么您可以复制它们,但是当第一个列表中的对象进行任何更改时,这些更改也会反映在第二个列表中。

      为此,有一个解决方案,

      1. 使用列表属性创建一个类
      2. 使用 Gson().toJson() 将该类对象转换为字符串
      3. 当您希望复制的列表再次将该字符串转换为 Class 对象时。
       public class MyMemo {
           private List<DemoClass> demoList;
       }
      
       MyMemo m = new Mymemo();
       m.demoList(..,..,)
      
       1. String s = Gson().toJson(m)
       2.Mymemo m = Gson().fromJson(s,Mymemo.java)
      

      【讨论】:

        猜你喜欢
        • 2013-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-26
        • 1970-01-01
        • 2012-09-30
        • 2016-02-15
        相关资源
        最近更新 更多