博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中实现对象克隆的方法
阅读量:4093 次
发布时间:2019-05-25

本文共 7397 字,大约阅读时间需要 24 分钟。

方式一:使用setter方法

Student stu1 = new Student();  stu1.setNumber(12345);  Student stu2 = new Student();  stu2.setNumber(stu1.getNumber());

方式二:实现Cloneable接口并重写Object类中的clone()方法

浅克隆: 当对象被复制时,只复制对象本身和其中包含的值类型成员变量,而引用类型成员对象并没有复制

public class Student implements Cloneable {    private int number;    public int getNumber() {        return number;    }    public void setNumber(int number) {        this.number = number;    }    //实现clone接口    @Override    public Object clone() {        Student stu = null;        try {            //浅克隆            stu = (Student) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return stu;    }    //测试克隆    public static void main(String[] args) {        Student stu1 = new Student();        stu1.setNumber(12345);        Student stu2 = (Student) stu1.clone();        System.out.println("学生1:  "+stu1.getNumber() + " " + stu1.hashCode());        System.out.println("学生2:  "+stu2.getNumber() + " " + stu2.hashCode());        stu2.setNumber(54321);        System.out.println("学生1:  "+stu1.getNumber() + " " + stu1.hashCode());        System.out.println("学生2:  "+stu2.getNumber() + " " + stu2.hashCode());    }}

运行结果:

学生1:  12345 1580066828学生2:  12345 491044090学生1:  12345 1580066828学生2:  54321 491044090

从程序的运行结果可以看出,学生2修改值类型变量(如int)number后,自身number值发生改变,但并不影响学生1

深克隆: 将原型对象的所有引用对象也复制一份给克隆对象

public class Student implements Cloneable {    private int number;    private Address add;    public void setAdd(Address add) {        this.add = add;    }    private Address getAdd(){        return this.add;    }    public void setNumber(int number){        this.number = number;    }    public int getNumber(){        return this.number;    }    @Override    public Object clone() {        Student stu = null;        try {            //浅复制            stu = (Student) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        //深度复制        stu.add = (Address) add.clone();        return stu;    }    public static void main(String[] args) {        Address add = new Address();        add.setAdd("北京市");        Student stu1 = new Student();        stu1.setNumber(12345);        stu1.setAdd(add);        Student stu2 = (Student) stu1.clone();        System.out.println("学生1:  " + stu1.getNumber() + ",地址:  " + stu1.getAdd().getAdd() + ", " + stu1.hashCode());        System.out.println("学生2:  " + stu2.getNumber() + ",地址:  " + stu2.getAdd().getAdd() + ", " + stu2.hashCode());        stu2.setNumber(54321);        add.setAdd("杭州市");        System.out.println("学生1:  " + stu1.getNumber() + ",地址:  " + stu1.getAdd().getAdd() + ", " + stu1.hashCode());        System.out.println("学生2:  " + stu2.getNumber() + ",地址:  " + stu2.getAdd().getAdd() + ", " + stu1.hashCode());    }}class Address implements Cloneable {    public String add;    @Override    protected Object clone() {        Address add = null;        try {            add = (Address) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return add;    }    public void setAdd(String add) {        this.add = add;    }    public String getAdd(){        return this.add;    }}

运行结果:

学生1:  12345,地址:  北京市, 1580066828学生2:  12345,地址:  北京市, 491044090学生1:  12345,地址:  杭州市, 1580066828学生2:  54321,地址:  北京市, 1580066828

当去掉上述代码中的stu.add = (Address) add.clone();时,运行结果如下。可以看出引用类型对象Address add并未复制到克隆对象中

学生1:  12345,地址:  北京市, 1580066828学生2:  12345,地址:  北京市, 491044090学生1:  12345,地址:  杭州市, 1580066828学生2:  54321,地址:  杭州市, 1580066828

方式三:实现Serializable接口

通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

Car类

import java.io.Serializable;public class Car implements Serializable {    private static final long serialVersionUID = 6880783148707693267L;    //品牌    private String brand;    //最高时速    private int maxSpeed;    public Car(String brand, int maxSpeed) {        this.brand = brand;        this.maxSpeed = maxSpeed;    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }    public int getMaxSpeed() {        return maxSpeed;    }    public void setMaxSpeed(int maxSpeed) {        this.maxSpeed = maxSpeed;    }}

Person类

import java.io.Serializable;public class Person implements Serializable {    private static final long serialVersionUID = 7592930394427200495L;    //姓名    private String name;    //年龄    private int age;    //座驾    private Car car;    public Person(String name, int age, Car car) {        this.name = name;        this.age = age;        this.car = car;    }    public Car getCar() {        return car;    }    public void setCar(Car car) {        this.car = car;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

CloneUtil类

import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class CloneUtil {    public static 
T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); }}

CloneTest类

public class CloneTest {    public static void main(String[] args) throws Exception {        Person person = new Person("lisi", 18, new Car("BMW", 300));        Person person1 = CloneUtil.clone(person);        System.out.println("person car before:" + person.getCar().getBrand() + " " + person.hashCode() + " " + person.getCar().hashCode());        System.out.println("person1 car before:" + person1.getCar().getBrand() + " " + person1.hashCode() + " " + person1.getCar().hashCode());        person1.getCar().setBrand("BYD");        System.out.println("person car after:" + person.getCar().getBrand() + " " + person.hashCode() + " " + person.getCar().hashCode());        System.out.println("person1 car after:" + person1.getCar().getBrand() + " " + person1.hashCode() + " " + person1.getCar().hashCode());    }}

运行结果

person car before:BMW 895328852 1304836502person1 car before:BMW 824909230 122883338person car after:BMW 895328852 1304836502person1 car after:BYD 824909230 122883338

备注1: 修改克隆的Person 对象person1 关联的 汽车对象 的品牌属性,原来的Person对象person关联的汽车不会受到任何影响,因为在克隆Person对象时其关联的Car对象也被克隆了

备注2: 基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过范型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译期完成的,不是在运行时抛出异常,这种方案明显优于使用Object类的clone方法克隆对象

方式四:通过org.apache.commons中的工具类BeanUtils和PropertyUtils进行对象复制

使用BeanUtils

try {  Student stu1 = new Student();  stu1.setNumber(12345);  Student stu2 = new Student();  BeanUtils.copyProperties(stu2, stu1);} catch (IllegalAccessException e) {  e.printStackTrace();} catch (InvocationTargetException e) {  e.printStackTrace();}

使用PropertyUtils

try {  Student stu1 = new Student();  stu1.setNumber(12345);  Student stu2 = new Student();  PropertyUtils.copyProperties(stu2, stu1);  catch (NoSuchMethodException e) {    e.printStackTrace();  }

两者区别:

BeanUtils提供了类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行自动转换;而PropertyUtils不支持这个功能,但是速度会更快一些。在实际开发中,BeanUtils使用更普遍,犯错的风险更低

转载地址:http://ketii.baihongyu.com/

你可能感兴趣的文章
4 岁小女孩给 Linux 内核贡献提交
查看>>
推荐几个私藏很久的技术公众号给大家
查看>>
20 个 2020 年软件开发趋势预测
查看>>
王垠受邀面试阿里 P9,被 P10 面跪后网上怒发文,惨打 325 的 P10 赵海平回应了!...
查看>>
Python 趣味打怪:147 段简单代码助你从入门到大师
查看>>
卧槽!小姐姐用动画图解 Git 命令,这也太秀了吧?!
查看>>
厉害了!Python 编辑器界的神器 Jupyter ,推出官方可视化 Debug 工具!
查看>>
卧槽!Java 虚拟机竟然还有这些性能调优技巧...
查看>>
听说玩这些游戏能提升编程能力?
查看>>
7 年工作经验,面试官竟然还让我写算法题???
查看>>
被 Zoom 逼疯的歪果仁,造出了视频会议机器人,同事已笑疯丨开源
查看>>
上古语言从入门到精通:COBOL 教程登上 GitHub 热榜
查看>>
再见,Eclipse...
查看>>
超全汇总!B 站上有哪些值得学习的 AI 课程...
查看>>
如果你还不了解 RTC,那我强烈建议你看看这个!
查看>>
神器面世:让你快速在 iOS 设备上安装 Windows、Linux 等操作系统!
查看>>
沙雕程序员在无聊的时候,都搞出了哪些好玩的小玩意...
查看>>
太赞了!GitHub 标星 2.4k+,《可解释机器学习》中文版正式开放!
查看>>
程序员用 AI 修复百年前的老北京视频后,火了!
查看>>
漫话:为什么你下载小电影的时候进度总是卡在 99% 就不动了?
查看>>