java:对象拷贝:Cloneable接口的浅拷贝、深拷贝,Serializable接口的深拷贝

1、对象拷贝:

对象拷贝,主要牵扯的是内存的问题,如User user =new User();拷贝(赋值)之后的新对象,和之前的老对象是否存在共用在堆上的内存问题。

tips:1、new出来的对象在堆上存在,主要就是判别这块。

          2、堆地址不同,深拷贝,原对象和新对象互不影响。反之,只要有部分的共用内存,就是浅拷贝

2、基本思路:

1、直接new一个新的对象,调用get、set方法。new了块新的内存,深拷贝,内存不共用。

后面不再赘述。

User user = new User(a,b,c);

User user2 = new User();

user2.setA(user.getA());

2、实现Cloneable接口的浅拷贝

实现Cloneable接口,并重写clone方法,实现对象的拷贝(其实也不完全是浅拷贝,当拷贝的内,内部没有自定义的类对象时也是深拷贝的。这块说是浅拷贝的,是因为有类变量)

3、实现Serializable接口的深拷贝

序列化是把对象的副本拷贝到流里面,再把流里面的对象反序列化,重而实现一个和原对象不同堆地址的深拷贝。注意的是,借用此方式实现深拷贝的类,下面的子类也必须实现Serializable接口。不然无法序列化,报错

此块和Cloneable接口的不一样,(实现cloneable接口的此类,下面的类对象类,可以/可以不 实现cloneable接口)

4、遇自定义类皆实现Cloneable接口深拷贝前面2、说的是浅拷贝

 

 

3、代码实现

1、new对象,直接set、get方法 省略

2、实现Cloneable接口的浅拷贝

class Door implements Cloneable{
     public  int doorNum;
     public String name;

    public Door(int doorNum, String name) {
        this.doorNum = doorNum;
        this.name = name;
    }
    public Door() {
    }
}

class Car implements Cloneable{
     int whell;
     Door door;//成员类 没有实现Cloneable接口

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

    public Car(int whell, Door door) {
        this.whell = whell;
        this.door = door;
    }
}

MainMethod:
 //2、实现Cloneable接口的
        Car car = new Car(4,new Door(2,"A"));
        Car car1 =(Car) car.clone();//这块,必须进行一个类型的强制转换
        System.out.println("car:"+car.door.doorNum+car.door.name+car.whell);
        System.out.println("car1:"+car1.door.doorNum+car1.door.name+car1.whell);
        //此时输出结果是一样的,car 和car1 内容一致

        car.whell=5;//实现了cloneable接口的类
        car.door.name = "B";//成员对象 没有实现cloneable接口

        System.out.println("car:"+car.door.doorNum+car.door.name+car.whell);
        System.out.println("car1:"+car1.door.doorNum+car1.door.name+car1.whell);//证实了是浅拷贝 只对当前类中的进行了深拷贝,对象类成员是浅拷贝
        //修改了car的whell 和door.name  外部Car类的其他成员(whell)是不一致的,证实了只有当前类中的非成员对象 是深度拷贝
        //door由于是引用类型  没有实现clone接口及方法  所以修改了door.name后 car和car1的都变了

3、实现Serializable接口的深拷贝

class Teacher implements Serializable{
    private static final long seriaVersionUID = -8099797912131114222L;
    public int age;
    public String name;

    public Teacher(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Teacher() {}
    //get set方法省略

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

class Student implements  Serializable{

   private static final long seriaVersionUID = -8099797912131114211L;

    public  int age;
    public String name;
    public Teacher teacher;

    public Student(int age, String name, Teacher teacher) {
        this.age = age;
        this.name = name;
        this.teacher = teacher;
    }

   //get set方法省略

    public Object DeepCopy() throws Exception{//使用序列化和反序列化 实现克隆的逻辑

        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();

    }
}

MainMethod

 //3、实现Seriliazble 接口的  这个实现方式,是完全的深度拷贝,即外部类和成员类对象,都实现了seriliable接口,那么外部类和类的其他类变量 都是new了份新的 内存分离

        Teacher teacher = new Teacher(40,"TeacherA");
        Student student=new Student(20,"StuA",teacher);

        Student student1 = (Student) student.DeepCopy();

        System.out.println("stu.age: "+student.getAge()+" stu.name: "+student.getName()+" stu.teacher: "+student.getTeacher().getName()+student.getTeacher().getAge());
        System.out.println("stu1.age: "+student1.getAge()+" stu1.name: "+student1.getName()+" stu1.teacher: "+student1.getTeacher().getName()+student1.getTeacher().getAge());

        System.out.println();


        student.getTeacher().setName("TeacherB");
        student.getTeacher().setAge(45);
        student.setAge(90);

        System.out.println("stu.age: "+student.getAge()+"stu.name: "+student.getName()+"stu.teacher: "+student.getTeacher().getName()+student.getTeacher().getAge());
        System.out.println("stu1.age: "+student1.getAge()+"stu1.name: "+student1.getName()+"stu1.teacher: "+student1.getTeacher().getName()+student1.getTeacher().getAge());

4、遇自定义类皆实现Cloneable接口深拷贝前面2、说的是浅拷贝

class User implements Cloneable {
    public String name;
    public Account account;

    @Override
    protected User clone() {
        try {
            User user = (User) super.clone();//当前类实现了cloneable接口 ,重写clone方法
            user.account = account.clone();//成员对象也实现了cloneable接口,重写了clone方法,所以整体上是深拷贝
            return user;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
 class Account implements Cloneable {
        public int id;
        public String name;
        public double count;

        @Override
        protected Account clone() {
            try {
                return (Account) super.clone();//类User的类变量 也实现cloneable接口及方法 最后才是深拷贝
                // 要是此类下还有public ClassA class;这样的类变量,那么这样的类也得实现cloneable接口  依次下去的都要实现 最后才能实现整体的深拷贝
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;

        }
    }

MainMethod
//4、Cloneable实现的深拷贝
        Account account=new Account();
        account.id=1001;
        account.name="张三的账户";
        account.count=10000;

        User user=new User();
        user.account=account;
        user.name="张三";

        //执行赋值操作
        User copyUser=user.clone();

        System.out.println("原数据:"+user);
        System.out.println("copy数据:"+copyUser);

        System.out.println("\n修改后:\n");
        //更改原数据
        user.name="李四";
        user.account.name="李四的账户";
        System.out.println("原数据:"+user);
        System.out.println("原数据的account对象:"+user.account);
        System.out.println("copy数据:"+copyUser);
        System.out.println("copy数据的account对象:"+copyUser.account);

总结:对象克隆的四种方式:

1、new新对象,直接调用get set,深拷贝,内存分离。

2、实现Cloneable接口的浅拷贝(之下有自定义类但实现Cloneable接口及方法)

3、实现Serializable接口的深拷贝(下面所有类都必须实现Serializable接口)

4、实现Cloneable接口的深拷贝(类及之下有自定义类都得实现Cloneable接口及方法)

 

实现Serializable接口的最方便,直接new对象的最好想,Cloneable的,类的嵌套少还可以,不然实现很多clone挺麻烦的,不太建议用。

参考:https://blog.csdn.net/u010838555/article/details/102690626

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

约翰兰博之西安分博

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

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

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

打赏作者

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

抵扣说明:

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

余额充值