深拷贝和浅拷贝是关于对象复制的概念,用来描述对象在被复制时所涉及的引用关系和对原始对象数据的影响。在Java中,实现深拷贝和浅拷贝有多种方式,下面将逐一介绍。

浅拷贝

浅拷贝是指复制对象时,仅仅复制对象本身以及对象中的基本类型属性,而不复制引用对象。被复制的对象和新创建的对象会指向同一个引用地址。

浅拷贝可以通过Java提供的Cloneable接口和clone()方法实现。clone()方法是Object类的一个protected方法,因此如果要实现浅拷贝,需要在自定义的类中重写clone方法,并将访问修饰符改为public。

浅拷贝示例:

public class Book implements Cloneable{
    private String title;
    private Author author;

    public Book(String title, Author author) {
        this.title = title;
        this.author = author;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public Author getAuthor() {
        return author;
    }

    @Override
    public Book clone() throws CloneNotSupportedException {
        return (Book) super.clone();
    }
}

public class Author {
    private String name;

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

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        Author author = new Author("Alice");
        Book book1 = new Book("Java Basic", author);
        try {
            Book book2 = book1.clone();
            book2.getAuthor().setName("Bob");
            System.out.println(book1.getAuthor().getName());  // 输出Bob
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

以上代码中,Book类中包含一个Author类的引用,通过浅拷贝的方式复制了book对象,并修改了复制对象中的author引用的name属性值。之后输出原始对象的author引用的name属性,结果为Bob,说明原始对象和复制对象共享了相同的author引用。

深拷贝

深拷贝是指复制对象时,不仅复制对象本身,还复制对象中的引用对象,被复制的对象和新创建的对象会指向不同的引用地址。

实现深拷贝的方式有多种,下面介绍两种常用的方式:使用拷贝构造函数和使用序列化与反序列化。

1. 使用拷贝构造函数:定义一个与当前类相同参数的构造函数,用于复制对象中的引用对象。

深拷贝示例:

public class Book {
    private String title;
    private Author author;

    public Book(String title, Author author) {
        this.title = title;
        this.author = author;
    }

    // 拷贝构造函数
    public Book(Book book) {
        this.title = book.title;
        this.author = new Author(book.author.getName());
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public Author getAuthor() {
        return author;
    }
}

public class Author {
    private String name;

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

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        Author author = new Author("Alice");
        Book book1 = new Book("Java Basic", author);
        Book book2 = new Book(book1);
        book2.getAuthor().setName("Bob");
        System.out.println(book1.getAuthor().getName());  // 输出Alice
    }
}

以上代码中,Book类中定义了一个拷贝构造函数,用于复制对象的author引用。在main函数测试时,通过拷贝构造函数复制了book对象,修改了复制对象中的author引用的name属性值。之后输出原始对象的author引用的name属性,结果为Alice,说明原始对象和复制对象分别拥有了各自的author引用。

2. 使用序列化与反序列化:通过将对象转化为字节流实现深拷贝。先将对象进行序列化,然后再将序列化后的字节流反序列化为对象。

深拷贝示例:

import java.io.*;

public class Book implements Serializable {
    private String title;
    private Author author;

    public Book(String title, Author author) {
        this.title = title;
        this.author = author;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public Author getAuthor() {
        return author;
    }

    // 序列化深拷贝
    public Book deepClone() {
        Book cloneBook = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            cloneBook = (Book) objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return cloneBook;
    }
}

public class Author implements Serializable {
    private String name;

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

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        Author author = new Author("Alice");
        Book book1 = new Book("Java Basic", author);
        Book book2 = book1.deepClone();
        book2.getAuthor().setName("Bob");
        System.out.println(book1.getAuthor().getName());  // 输出Alice
    }
}

以上代码中,Book类和Author类实现了Serializable接口,并在Book类中定义了一个deepClone()方法,用于通过序列化和反序列化实现深拷贝。在main函数测试时,通过deepClone()方法复制了book对象,修改了复制对象中的author引用的name属性值。之后输出原始对象的author引用的name属性,结果为Alice,说明原始对象和复制对象分别拥有了各自的author引用。

综上所述,浅拷贝和深拷贝分别涉及对象的引用复制和对象内部引用对象的复制。通过实现Cloneable接口和重写clone()方法,可以实现浅拷贝;通过拷贝构造函数和序列化与反序列化,可以实现深拷贝。根据具体的场景需求,选择合适的方式来进行对象复制。
本文由轻山版权所有,禁止未经同意的情况下转发