将ArrayList传递给副本构造函数时是否需要深层复制?

时间:2018-06-21 17:29:35

标签: java design-patterns arraylist constructor cloning

我正在尝试找出实现我正在研究的代码的最佳方法。

关于如何将数据传递给构造函数,我有两种选择。

第一种方式

<div id="greetings" style="overflow: hidden" #vars>
  <div *ngIf="(vars.style.overflow === 'hidden')">
      Hello universe!
  </div>
</div>

第二种方式

private String ISBN;
private String title;
private ArrayList <Person>authors = new ArrayList<>();
private ArrayList <BookCategory>subjectCategories = new ArrayList<>();


public Book (String isbn, String title,
        ArrayList <Person>authors, ArrayList <BookCategory>categories) {

    //call the checkISBN method
    boolean check = checkISBN(isbn);
    if (check ==true) {
        this.ISBN= isbn;
    }
    else {
        throw new IllegalArgumentException("Invalid ISBN");
    }
    this.title = title;
    for(int index =0; index<authors.size(); index++) {
        this.authors.add(authors.get(index));
    }
}

有什么不同吗?

我不确定,因为似乎没有必要使用作者private String ISBN; private String title; private ArrayList <Person>authors = new ArrayList<>(); private ArrayList <BookCategory>subjectCategories = new ArrayList<>(); public Book (String isbn, String title, ArrayList <Person>authors, ArrayList <BookCategory>categories) { //call the checkISBN method boolean check = checkISBN(isbn); if (check ==true) { this.ISBN= isbn; } else { throw new IllegalArgumentException("Invalid ISBN"); } this.title = title; this.authors = authors; } 的副本而不是原始的Book来声明ArrayList

正确的方法是什么?为什么?

2 个答案:

答案 0 :(得分:0)

如果您进行复制,则需要花费一些时间来获得安全性。如果您没有复制,那么客户可以与一些作者一起构建Book,然后更改作者,这将反映在Book中:

List<Person> authors = new ArrayList<>();
authors.add(new Person("J.K. Rowling"));
Book harryPotter = new Book("some ISBN", "Harry Potter", authors, new ArrayList<>());
// Harry Potter is written by J.K. Rowling.

authors.set(1, new Person("pkpnd"));
// Harry Potter is now written by pkpnd??

如果这在您的用例中听起来很糟糕,则应该进行复制。

请注意,您执行的不是 deep 复制,而是浅表复制。复制时,您需要创建全新的Person对象:

this.authors = new ArrayList<>();
for (Person p : authors) {
    this.authors.add(new Person(p.getName()));
}

答案 1 :(得分:0)

这是一个如何使用serialization进行类的深层复制的示例。这样可以确保所有内容都是全新的参考:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Person implements Serializable{

    private static final long serialVersionUID = 1L;
    private String name;

    public Person(String name) {this.name = name;}

    public String setName(String name) {return this.name = name;}

    /**
     * make a deep copy with serialization without creating files
     * convert class object to a stream of bytes then restore it
     */
    public Person deepCopy() {  
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            oos.flush();
            oos.close();
            bos.close();

            return (Person) new ObjectInputStream(
                    new ByteArrayInputStream(bos.toByteArray())).readObject();

        } catch (IOException  | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }



    public static void main(String[] args) {
        // Test
        Person p1 = new Person("Yahya");
        Person p2 = p1;
        Person p3 = p1.deepCopy();

        // change the original object and check if that affect the others
        p1.setName("Uknown");           
        System.out.println("P1: " + p1.name + " ... P2: " + p2.name 
                                            + " ... P3: " + p3.name);

    }
}

输出

P1: Uknown ... P2: Uknown ... P3: Yahya