java浅拷贝和深拷贝的区别???

java浅拷贝和深拷贝的区别???

  • 假设创建一个对象A然后在将A对象赋值给B、此时你操作了B对象等同于你操作了A对象、原因就是因为他们的内存地址指向的是同一块区域、可以叫做引用的拷贝

    User user1 = new User();
    User user2 = user1;
    
    // 输出结果
    user1地址:demo4.User@7f31245a
    user2地址:demo4.User@7f31245a
    
  • 注意点:

  • public class User implements Cloneable{   // 实现Cloneable接口
    
      @Override   // 从写Object类中的clone()方法
      protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 主要还是调用Object类中的clone()方法
      }
    }
    
  • 拷贝的共同目的就是为了拷贝一个全新的对象、

浅拷贝(Shallow Copy)

浅拷贝(Shallow Copy)

案例:

Hobby类

public class Hobby{
    private String hobbyName;

    public Hobby() {
    }
    public Hobby(String hobbyName) {
        this.hobbyName = hobbyName;
    }

    public String getHobbyName() {
        return hobbyName;
    }

    public void setHobbyName(String hobbyName) {
        this.hobbyName = hobbyName;
    }

    public String toAddress() {
        return super.toString();
    }


    @Override
    public String toString() {
        return "ID{" +
                "hobbyName=" + hobbyName +
                '}';
    }
}

User类

public class User implements Cloneable{
    private String name;
    private Integer age;
    private Hobby hobby;

    public User() {
    }

    public User(String name, Integer age, Hobby id) {
        this.name = name;
        this.age = age;
        this.hobby = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Hobby getHobby() {
        return hobby;
    }

    public void setHobby(Hobby hobby) {
        this.hobby = hobby;
    }

    public String toAddress() {
        return super.toString();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", Hobby=" + hobby +
                '}';
    }
		// 从写clone方法()
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

测试类

public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Hobby hobby = new Hobby("唱歌");
        User user1 = new User("小明",18,hobby);
        User user2 = (User) user1.clone();
        System.out.println("============初始内容==========");
        System.out.println("user1地址:"+user1.toAddress()+"\t\tuser2地址:"+user2.toAddress());
        System.out.println("user1的Hobby地址:"+user1.getHobby().toAddress()+"\t\t" +
                "user2的Hobby地址:"+user2.getHobby().toAddress());
        System.out.println("user1:"+user1.toString());
        System.out.println("user2:"+user2.toString());
        user2.setName("小红");
        user2.setAge(17);
        hobby.setHobbyName("跳舞");
        user2.setHobby(hobby);
        System.out.println("============值赋完内容==========");
        System.out.println("user1的Hobby地址:"+user1.getHobby().toAddress()+"\t\t" +
                "user2的Hobby地址:"+user2.getHobby().toAddress());
        System.out.println("user1的Hobby地址:"+user1.toString());
        System.out.println("user2的Hobby地址:"+user2.toString());

    }
}

测试结果:

============初始内容==========
user1地址:demo4.User@7f31245a		user2地址:demo4.User@6d6f6e28
user1的Hobby地址:demo4.Hobby@135fbaa4		user2的Hobby地址:demo4.Hobby@135fbaa4
user1:User{name='小明', age=18, Hobby=ID{hobbyName=唱歌}}
user2:User{name='小明', age=18, Hobby=ID{hobbyName=唱歌}}
============值赋完内容==========
user1的Hobby地址:demo4.Hobby@135fbaa4		user2的Hobby地址:demo4.Hobby@135fbaa4
user1的Hobby地址:User{name='小明', age=18, Hobby=ID{hobbyName=跳舞}}
user2的Hobby地址:User{name='小红', age=17, Hobby=ID{hobbyName=跳舞}}

个人小结:

  • 浅拷贝简单来说就是将一个对象new了两次、但是和浅拷贝性质不一样、浅拷贝实际意义是将上一个对象拷贝一份、将其对象数据拷贝到新地址中、而最后达到两个对象的引用地址不一样。
  • 浅拷贝的特点
    • 对应基本数据类型的成员变量: 基础类型的拷贝,其中一个对象修改该值,不会影响另外一个、原因是 因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象 。
    • 对应引用类型的成员变量:比如数组或者类对象、改变其中一个,会对另外一个也产生影响 、原因是因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。

弊端:浅拷贝只对本身要拷贝的对象作为拷贝、而不会将拷贝对象中的引用类型属性再次进行拷贝。

深拷贝 (Deep Copy)

深拷贝 (Deep Copy)

案例:

Hobby类

public class Hobby implements Cloneable{
    private String hobbyName;

    public Hobby() {
    }
    public Hobby(String hobbyName) {
        this.hobbyName = hobbyName;
    }

    public String getHobbyName() {
        return hobbyName;
    }

    public void setHobbyName(String hobbyName) {
        this.hobbyName = hobbyName;
    }

    public String toAddress() {
        return super.toString();
    }


    @Override
    public String toString() {
        return "ID{" +
                "hobbyName=" + hobbyName +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

User类

public class User implements Cloneable{
    private String name;
    private Integer age;
    private Hobby hobby;

    public User() {
    }

    public User(String name, Integer age, Hobby id) {
        this.name = name;
        this.age = age;
        this.hobby = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Hobby getHobby() {
        return hobby;
    }

    public void setHobby(Hobby hobby) {
        this.hobby = hobby;
    }

    public String toAddress() {
        return super.toString();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", Hobby=" + hobby +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user = (User) super.clone();
        hobby = (Hobby)getHobby().clone();
        return user;
    }
}

测试类

public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Hobby hobby = new Hobby("唱歌");
        User user1 = new User("小明",18,hobby);
        User user2 = (User) user1.clone();
        System.out.println("============初始内容==========");
        System.out.println("user1地址:"+user1.toAddress()+"\t\tuser2地址:"+user2.toAddress());
        System.out.println("user1的Hobby地址:"+user1.getHobby().toAddress()+"\t\t" +
                "user2的Hobby地址:"+user2.getHobby().toAddress());
        System.out.println("user1:"+user1.toString());
        System.out.println("user2:"+user2.toString());
        user2.setName("小红");
        user2.setAge(17);
        hobby.setHobbyName("跳舞");
        user2.setHobby(hobby);
        System.out.println("============值赋完内容==========");
        System.out.println("user1的Hobby地址:"+user1.getHobby().toAddress()+"\t\t" +
                "user2的Hobby地址:"+user2.getHobby().toAddress());
        System.out.println("user1的Hobby地址:"+user1.toString());
        System.out.println("user2的Hobby地址:"+user2.toString());

    }
}

测试结果

============初始内容==========
user1地址:demo4.User@7f31245a		user2地址:demo4.User@6d6f6e28
user1的Hobby地址:demo4.Hobby@135fbaa4		user2的Hobby地址:demo4.Hobby@45ee12a7
user1:User{name='小明', age=18, Hobby=ID{hobbyName=唱歌}}
user2:User{name='小明', age=18, Hobby=ID{hobbyName=唱歌}}
============值赋完内容==========
user1的Hobby地址:demo4.Hobby@135fbaa4		user2的Hobby地址:demo4.Hobby@45ee12a7
user1的Hobby地址:User{name='小明', age=18, Hobby=ID{hobbyName=唱歌}}
user2的Hobby地址:User{name='小红', age=17, Hobby=ID{hobbyName=跳舞}}

个人小结:

  • 深拷贝除了拷贝对象本身、对象内部的属性引用也会进行拷贝、唯一麻烦的就是在对象内部的属性的对象要去实现Cloneable接口、还要从写clone()方法、而本身对象的clone()方法中要对属性引用对象调用clone()方法将其赋值给这个引用对象属性
  • 深拷贝的特点
    • 对应基本数据类型的成员变量: 基础类型的拷贝,其中一个对象修改该值,不会影响另外一个、原因是 因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象 。(和浅拷贝一样)
    • 对应引用类型的成员变量:比如数组或者类对象、改变其中一个, 不会对另外一个也产生影响 、原因是因为深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间 。
  • 弊端
    • 如有对象属性是一个对象、就非常麻烦、需要每个对象实现Cloneable接口、并从写clone()方法、并在上一个对象的clone()方法中去调用属性对象的clone()将其拷贝后赋值给属性。
    • 深拷贝的开销大

浅拷贝和深拷贝总结

  • 不管还是浅拷贝还是深拷贝、它们两的作用就是复制对象、复制后的对象和被复制的对象引用地址不一样、可以简单理解为将复制的对象放在一个新的内存区域中。
  • 浅拷贝可以复制对象的基本类型和引用类型、只不过引用类型指向的是同一片内存空间
  • 深拷贝可以复制对象的基本类型和引用类型、只不过引用类型指向的不是同一片内存空间

参考: https://www.jianshu.com/p/94dbef2de298

采用序列化对象的形式来实现深度克隆

什么是序列化、序列化就是将内存中的对象保存在硬盘中、当做一个文件、然后将文件读取出来变成内存中的对象、这个形式是反序列化。

@Test
    public void fun_5() throws Exception {
        /**
         *  注意:
         *      User对象需要实现Serializable接口
         */
        Hobby hobby = new Hobby();
        User user1 = new User("小明",18,hobby);  // 创建新对象
        String projectPath = System.getProperty("user.dir");  // 获取当前项目路径
        System.out.println(projectPath);
        File f = new File(projectPath+"/obj.txt"); // 文件报存的本地地址
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f)); // 输出流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));// 输入流

        oos.writeObject(user1);  // 将对象序列化

        User user2 = (User) ois.readObject();// 将对象反序列化

        System.out.println("user1地址:"+user1.toAddress()+"\t\tuser2地址:"+user2.toAddress());
        System.out.println("user1的Hobby地址:"+user1.getHobby().toAddress()+"\t\t" +
                "user2的Hobby地址:"+user2.getHobby().toAddress());

        ois.close(); // 释放资源
        oos.close(); // 释放资源

}

对象(反)序列化、要实现Serializable接口、否则会报一个错误

java.io.NotSerializableException: pojo.User

·测试结果

user1地址:demo4.User@5fdef03a		user2地址:demo4.User@2c13da15
user1的Hobby地址:demo4.Hobby@5ccd43c2		user2的Hobby地址:demo4.Hobby@77556fd

具体了解还请自行测试。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值