首页 > 其他分享 >浅拷贝深拷贝2

浅拷贝深拷贝2

时间:2024-07-14 13:57:17浏览次数:7  
标签:name age Writer writer1 writer2 book 拷贝

// 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}}
     */
}

标签:name,age,Writer,writer1,writer2,book,拷贝
From: https://www.cnblogs.com/sprinining/p/18301484

相关文章

  • 对象的生存期 内存 深度拷贝 拷贝构造函数 笔记
    栈上的东西如何存在?栈是类似一种数据结构,像摞在桌子上的一堆书,要看中间的书需要把上面的书拿走作用域:形象成一本书,书内声明的变量作用域结束,要把这本书从书堆中拿出来作用域指针是什么:基本是个类是一个指针的包装器,在构造时用堆分配指针析构时删除指针,可以实现自动化new......
  • 深入解析C++中的特殊成员函数:构造函数、析构函数、拷贝构造函数与赋值操作符
    深入解析C++中的特殊成员函数:构造函数、析构函数、拷贝构造函数与赋值操作符在C++编程的浩瀚宇宙中,构造函数、析构函数、拷贝构造函数和赋值操作符是构成对象生命周期和行为的四大基石。它们各自扮演着不可或缺的角色,确保了对象从创建到销毁,从复制到赋值的整个过程既安全又......
  • 构造、析构、拷贝(Semantics of Construction,Destruction,and Copy)
    1、继承体系下的对象构造当我定义一个object如下Tobject;如果T有一个默认构造函数,它会被调用。比较不明显的是构造函数内部有大量的隐藏代码,因为编译器会扩充构造函数,一般而言编译器所做的扩充如下:记录在成员初始化列表中的数据成员初始化操作会被放到构造函数体中,并......
  • 【JavaScript】聊一聊js中的浅拷贝与深拷贝与手写实现
    前言什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。‌在聊深浅拷贝之前咱得了解一下js中的两种数据类型:基本数据类型(6种)String、Number、Object、Boolean、null、undefined、symbol(ES6+)引用数据类型Object(function、Array、正则表达式等皆......
  • 游戏陪玩app开发,必须知道的拷贝代码
    游戏陪玩app开发,必须知道的拷贝代码(数组/对象)(深/浅)拷贝letlist=[{name:"o"}];letobj={stu:{name:"o"}};//数组浅拷贝letlistCopy1=[].concat(list);letlistCopy2=list.slice();letlistCopy3=Array.from(list);letlistCopy4=[...li......
  • java实现浅拷贝与深拷贝
    目录浅拷贝 深拷贝实现cloneable接口序列化浅拷贝浅拷贝是指创建一个新的对象,该对象的内容是原始对象中各项的引用。换句话说,浅拷贝仅复制了原始对象中元素的引用,而不是元素本身的拷贝classPeopleimplementsCloneable{privateStringname;privateint......
  • OpenCV中的浅拷贝和深拷贝
    文章目录前言一、浅拷贝二、深拷贝三、比较总结前言在数字图像处理中,针对读取到的一张图像,需要反复利用这张图像做各种的变换,以满足我们项目的需求。在这之前,最容易忽略的一点就是图像之间的拷贝问题,其中的浅拷贝和深拷贝不仅影响数据的存储方式,还直接关系到内存管......
  • JavaScript复习记录(2)— 浅拷贝&深拷贝
    1、前情概要1.1、基本数据类型    Number、String、Boolean、Null、Undefined、Symbol、BigInt。基本数据类型是直接存储在栈中的数据。1.2、引用数据类型    Object、Array、Function、Date、RegExp、Map、Set、WeekMap、WeekSet、Promise、Error、Buffe......
  • js浅拷贝与深拷贝的区别和实现方式
           ......
  • 浅拷贝和深拷贝的区别
    一、数据类型在讨论深浅拷贝之前,我们先说说数据类型,因为深浅拷贝与数据类型有关。数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol(es6引入的一种类型))和引用数据类型(Object、Array、Function)。基本数据类型特点:直接存储在栈中;引用数据类型:它真......