简体   繁体   English

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

[英]Is deep copy necessary on passing an ArrayList to a copy constructor?

I'm trying to figure out the best way to implement the code I'm working on. 我正在尝试找出实现我正在研究的代码的最佳方法。

I have two options of how to pass the data to my constructor. 对于如何将数据传递给构造函数,我有两种选择。

First way 第一种方式

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

Second way 第二种方式

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

Does it make a difference? 这有什么不同吗?

I'm not sure because it seems like it would be unnecessary to declare the Book with a copy of the Authors ArrayList instead of the original ArrayList . 我不确定,因为似乎没有必要使用Authors ArrayList的副本而不是原始ArrayList来声明Book

What is the correct way to do this, and why? 正确的方法是什么?为什么?

If you copy, you spend some time to gain security. 如果您进行复制,则需要花费一些时间来获得安全性。 If you didn't copy, then a client could construct a Book with some authors and later change the authors which will be reflected in the Book : 如果您不进行复制,那么客户可以与一些作者一起构造一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??

If that sounds bad in your use case, you should make a copy. 如果这在您的用例中听起来很糟糕,则应进行复制。

Note that you aren't performing a deep copy, only a shallow copy. 请注意,您不是在执行深层复制,而只是执行浅层复制。 You'll need to create entirely new Person objects when copying: 复制时,您需要创建全新的Person对象:

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

This is an example of how to make a deep copy of your class with serialization . 这是一个如何通过serialization对类进行深层复制的示例。 This ensures everything is a brand new reference: 这样可以确保所有内容都是全新的参考:

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

    }
}

Output 输出量

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM