Java中深拷贝与浅拷贝

浅拷贝的定义:

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此在浅拷贝中,克隆对象只会赋值原始对象的值类型成员变量(基本数据类型),而引用数据类型也只是赋值了一份原始对象的引用变量的地址。

​ 浅拷贝

实现浅拷贝的方法(implements cloneable):

public class ShallowCopy{
    public static void main(String[] args) throws CloneNotSupportedException {
        Song song = new Song("1" , "thank you next" , "I might say ....");
        Singer singer = new Singer("1" , "Ariana Grande" , song);
        System.out.println(singer);
        Singer cloneSinger = (Singer) singer.clone();
        System.out.println(cloneSinger);
        cloneSinger.getSong().setId("2");
        cloneSinger.getSong().setName("one last time");
        cloneSinger.getSong().setLyrics("I need to be the one");
        System.out.println(singer);
        System.out.println(cloneSinger);
    }
}
public class Song{
    private String id;
    private String name;
    private String lyrics;

    public Song() {
    }

    public Song(String id, String name, String lyrics) {
        this.id = id;
        this.name = name;
        this.lyrics = lyrics;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getLyrics() {
        return lyrics;
    }

    public void setLyrics(String lyrics) {
        this.lyrics = lyrics;
    }

    @Override
    public String toString() {
        return "Song{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", lyrics='" + lyrics + '\'' +
                '}';
    }
}
public class Singer implements Cloneable{
    private String id;
    private String name;
    private Song song;

    public Singer() {
    }

    public Singer(String id, String name, Song song) {
        this.id = id;
        this.name = name;
        this.song = song;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Song getSong() {
        return song;
    }

    public void setSong(Song song) {
        this.song = song;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Singer clone = null;
        clone = (Singer) super.clone();
        return clone;
    }

    @Override
    public String toString() {
        return "Singer{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", song=" + song +
                '}';
    }
}

最终从结果我么可以知道:

Singer{id='1', name='Ariana Grande', song=Song{id='1', name='thank you next', lyrics='I might say ....'}}
Singer{id='1', name='Ariana Grande', song=Song{id='1', name='thank you next', lyrics='I might say ....'}}
Singer{id='1', name='Ariana Grande', song=Song{id='2', name='one last time', lyrics='I need to be the one'}}
Singer{id='1', name='Ariana Grande', song=Song{id='2', name='one last time', lyrics='I need to be the one'}}

我们只对克隆对象cloneSinger里的进行了Song的修改,但原对象的Song对象也随之变化,所以克隆对象cloneSinger与原对象singer中引用对象song是共用的,我们在修改cloneSinger的同时,singer也发生了改变,所以二者对于song对象的引用,指向的是同一个地址,可以得出在浅拷贝中,克隆对象只会赋值原始对象的值类型成员变量(基本数据类型),而引用数据类型也只是赋值了一份原始对象的引用变量的地址。

深拷贝的定义:

深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。此时拷贝出来的新对象,会将原始对象的所有类型进行拷贝。

​ 深拷贝

实现深拷贝的方法(implements cloneable):

public class DeepCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Song song = new Song("1" , "止战之殇" , "光,轻如纸张.....");
        Singer singer = new Singer("1" , "周杰伦" , song);
        // 对歌手进行deep copy
        Singer cloneSinger = (Singer) singer.clone();
        cloneSinger.setId("one");
        cloneSinger.getSong().setId("2");
        cloneSinger.getSong().setName("晴天");
        cloneSinger.getSong().setLyrics("刮风这天,我试过握着你手...");
        //对cloneSinger与singer进行比较
        System.out.println(singer);
        System.out.println(cloneSinger);
    }
}

public class Singer implements Cloneable{
    private String id;
    private String name;
    private Song song;

    public Singer() {
    }

    public Singer(String id, String name, Song song) {
        this.id = id;
        this.name = name;
        this.song = song;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Song getSong() {
        return song;
    }

    public void setSong(Song song) {
        this.song = song;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Singer clone = null;
        clone = (Singer) super.clone();
        clone.setSong((Song) clone.getSong().clone());
        return clone;
    }

    @Override
    public String toString() {
        return "Singer{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", song=" + song +
                '}';
    }
}
public class Song implements Cloneable{
    private String id;
    private String name;
    private String lyrics;

    public Song() {
    }

    public Song(String id, String name, String lyrics) {
        this.id = id;
        this.name = name;
        this.lyrics = lyrics;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getLyrics() {
        return lyrics;
    }

    public void setLyrics(String lyrics) {
        this.lyrics = lyrics;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Song clone = null;
        clone = (Song) super.clone();
        return clone;
    }

    @Override
    public String toString() {
        return "Song{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", lyrics='" + lyrics + '\'' +
                '}';
    }
}

我们可以看到结果

Singer{id='1', name='周杰伦', song=Song{id='1', name='止战之殇', lyrics='光,轻如纸张.....'}}
Singer{id='one', name='周杰伦', song=Song{id='2', name='晴天', lyrics='刮风这天,我试过握着你手...'}}

实现深拷贝的方法(implements Serializable):

public class DeepCopySerializable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Song song = new Song("1" , "我不配" , "这街道太拥挤,太多人有秘密.....");
        Singer singer = new Singer("1" , "周杰伦" , song);
        // 对歌手进行deep copy
        Singer cloneSinger = (Singer) singer.clone();
        cloneSinger.setId("①");
        cloneSinger.getSong().setId("2");
        cloneSinger.getSong().setName("给我一首歌的时间");
        cloneSinger.getSong().setLyrics("能不能给我一首歌的时间...");
        //对cloneSinger与singer进行比较
        System.out.println(singer);
        System.out.println(cloneSinger);
    }
}

public class Singer implements Serializable {
    private String id;
    private String name;
    private Song song;

    public Singer() {
    }

    public Singer(String id, String name, Song song) {
        this.id = id;
        this.name = name;
        this.song = song;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Song getSong() {
        return song;
    }

    public void setSong(Song song) {
        this.song = song;
    }

    public Object clone() {
        Singer singer  = null;
        try { 
            // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            // 将流序列化成对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            singer = (Singer) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return singer;
    }


    @Override
    public String toString() {
        return "Singer{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", song=" + song +
                '}';
    }
}

public class Song implements Serializable {
    private String id;
    private String name;
    private String lyrics;

    public Song() {
    }

    public Song(String id, String name, String lyrics) {
        this.id = id;
        this.name = name;
        this.lyrics = lyrics;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getLyrics() {
        return lyrics;
    }

    public void setLyrics(String lyrics) {
        this.lyrics = lyrics;
    }

    @Override
    public String toString() {
        return "Song{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", lyrics='" + lyrics + '\'' +
                '}';
    }
}

可以看到结果:

Singer{id='1', name='周杰伦', song=Song{id='1', name='我不配', lyrics='这街道太拥挤,太多人有秘密.....'}}
Singer{id='①', name='周杰伦', song=Song{id='2', name='给我一首歌的时间', lyrics='能不能给我一首歌的时间...'}}

引用数据类型的id(String)和Song对象均进行了拷贝,不像浅拷贝那样,共用一个引用对象,而是有一个新的对象在堆上被创建了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Harlotte_Astrid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值