🛸~~ 🚁🚁🚁🛩️🛩️�|

n1ce2cv

园龄:5年2个月粉丝:4关注:1

浅拷贝深拷贝2

// Cloneable 接口是一个标记接口,用来表示某个功能在执行的时候是合法的
public interface Cloneable {
}

没有引用类型字段时

class Writer implements Cloneable {
private int age;
private String name;
// get,set和构造函数
@Override
public String toString() {
return "Writer{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
  • 如果一个类没有实现 Cloneable 接口,即便它重写了 clone() 方法,依然是无法调用该方法进行对象克隆的,程序在执行 clone() 方法的时候会抛出 CloneNotSupportedException 异常
public static void main(String[] args) throws CloneNotSupportedException {
Writer writer1 = new Writer(18, "二狗");
Writer writer2 = (Writer) writer1.clone();
System.out.println("浅拷贝后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
writer2.setName("铁蛋");
System.out.println("调整了 writer2 的 name 后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
/*
浅拷贝后:
writer1:Writer{age=18, name='二狗'}
writer2:Writer{age=18, name='二狗'}
调整了 writer2 的 name 后:
writer1:Writer{age=18, name='二狗'}
writer2:Writer{age=18, name='铁蛋'}
*/
}
  • 字符串 String 是不可变对象,一个新的值必须在字符串常量池中开辟一段新的内存空间,所以并没有影响到字符串二狗的值

有引用类型字段时

浅拷贝

class Book {
private String bookName;
private int price;
// get,set和构造函数
@Override
public String toString() {
return super.toString().substring(26) +
" bookName='" + bookName + '\'' +
", price=" + price +
'}';
}
}
class Writer implements Cloneable {
private int age;
private String name;
// 新加了个自定义的引用类型字段
private Book book;
// get,set和构造函数
@Override
public String toString() {
return "Writer{" +
"age=" + age +
", name='" + name + '\'' +
", book=" + book +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Writer writer1 = new Writer(18,"二狗",new Book("编译原理",100));
Writer writer2 = (Writer) writer1.clone();
System.out.println("浅拷贝后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
Book book = writer2.getBook();
book.setBookName("离散数学");
book.setPrice(70);
System.out.println("writer2.book 变更后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
/*
浅拷贝后:
writer1:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2.book 变更后:
writer1:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=70}}
writer2:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=70}}
*/
}
  • writer2.book 变更后,writer1.book 也发生了改变。自定义对象的内存地址并没有发生改变,只是对应的字段值发生了改变

  • 浅拷贝克隆的对象中,引用类型的字段指向的是同一个,当改变任何一个对象,另外一个对象也会随之改变,除去字符串的特殊性外

深拷贝

  • 深拷贝和浅拷贝不同的,深拷贝中的引用类型字段也会克隆一份,当改变任何一个对象,另外一个对象不会随之改变
class Book implements Cloneable{
private String bookName;
private int price;
// get,set和构造函数
@Override
public String toString() {
return super.toString().substring(26) +
" bookName='" + bookName + '\'' +
", price=" + price +
'}';
}
// 重写了 clone() 方法,并实现了 Cloneable 接口。为的就是深拷贝的时候也能够克隆该字段。
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Writer implements Cloneable {
private int age;
private String name;
private Book book;
// get,set和构造函数
@Override
public String toString() {
return "Writer{" +
"age=" + age +
", name='" + name + '\'' +
", book=" + book +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 不再只调用 Object 的 clone() 方法对 Writer 进行克隆了
Writer writer = (Writer) super.clone();
// 还对 Book 也进行了克隆
writer.setBook((Book) writer.getBook().clone());
return writer;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Writer writer1 = new Writer(18,"二狗",new Book("编译原理",100));
Writer writer2 = (Writer) writer1.clone();
System.out.println("深拷贝后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
Book book = writer2.getBook();
book.setBookName("离散数学");
book.setPrice(70);
System.out.println("writer2.book 变更后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
/*
深拷贝后:
writer1:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2.book 变更后:
writer1:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=100}}
writer2:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=70}}
*/
}
  • 通过 clone() 方法实现的深拷贝比较笨重,因为要将所有的引用类型都重写 clone() 方法

使用序列化实现深拷贝

class Book implements Serializable {
private String bookName;
private int price;
...
}
class Writer implements Serializable {
private int age;
private String name;
private Book book;
...
//深度拷贝
public Object deepClone() throws IOException, ClassNotFoundException {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Writer writer1 = new Writer(18, "二狗", new Book("编译原理", 100));
Writer writer2 = (Writer) writer1.deepClone();
System.out.println("深拷贝后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
Book book = writer2.getBook();
book.setBookName("离散数学");
book.setPrice(70);
System.out.println("writer2.book 变更后:");
System.out.println("writer1:" + writer1);
System.out.println("writer2:" + writer2);
/*
深拷贝后:
writer1:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2:Writer{age=18, name='二狗', book=86 bookName='编译原理', price=100}}
writer2.book 变更后:
writer1:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=100}}
writer2:Writer{age=18, name='二狗', book=86 bookName='离散数学', price=70}}
*/
}

本文作者:n1ce2cv

本文链接:https://www.cnblogs.com/sprinining/p/18301484

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   n1ce2cv  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起