带有java中自定义对象的列表的深层副本

时间:2018-02-02 03:56:12

标签: java android

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

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项目中的addcopyList新项目。 clone()也受影响。如何确保copyList不引用相同的内存地址。

更新

建议使用clone()。但问题是我的自定义对象中有一个列表。我怎样才能$pdf = new FPDI('L', 'mm', array('119.888','50.038')); $pdf->setPrintHeader(false); $pdf->AddPage(); $page = $pdf->setSourceFile('aw_print.PDF'); $page = $pdf->ImportPage(1, 'TrimBox'); $pdf->useTemplate($page, 0, 0); $x = 10; $y = 10; $style = array( 'border' => 1, 'vpadding' => 'auto', 'hpadding' => 'auto', 'fgcolor' => array(0,0,0), 'bgcolor' => false, //array(255,255,255) 'module_width' => 1, // width of a single module in points 'module_height' => 1 // height of a single module in points ); $pdf->write2DBarcode('www.tcpdf.org', 'QRCODE,H', 10, 10, 60, 60, $style, 'N'); $pdf->Output('test.PDF', 'D'); 他们?

5 个答案:

答案 0 :(得分:6)

创建第一个列表时:

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());
}

我更喜欢使用复制构造函数。您可以阅读有关使用clone vs copy构造函数的good article by Josh Block in Effective Java

答案 1 :(得分:4)

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

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 :(得分:0)

以下所有选项都会生成浅层副本,这意味着更改一个数组中的值会影响第二个。它没有线程安全

1

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

2

        `Collection.copy(a,b)`

3

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

如果您应该迭代列表,并在此列表中添加元素,则创建新副本。这是深层拷贝

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

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

为此,有一个解决方案,

  1. 使用列表属性创建一个类
  2. 使用Gson()。toJson()将该类对象转换为String
  3. 当您想要再次复制列表时,将该String转换为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)