目录

对象克隆

浅克隆

深克隆

多层克隆


对象克隆

在讨论对象克隆之前, 可能会有人说 , 不能直接new一个吗?为什么要克隆

首先关于这个问题, 直接new一个对象, 这个对象里面包含的成员变量是null的 , 那问题又来了, 我不能去一个个set对象的值吗? 当然可以, 但这样麻烦, 对象克隆采用的是native方法,效率更高

那么该怎样去克隆呢? 克隆又分为浅克隆和深克隆

首先这样的方式不叫克隆 (这种只能叫做引用复制):

Object obj1 = new Object();
Object obj2 = obj1;

怎样区分是浅克隆还是深克隆呢?

在java中, 数据类型分为基本类型和引用类型 , 在复制数据的过程中, 基本类型的值会直接被复制过去, 但是引用类型只能复制引用的地址 , 所以深浅克隆的区别就是是否将引用类型所指向的变量也复制了

浅克隆

先来看浅克隆 , 有两种实现方式, 一是重写Object类中的clone() 方法, 二是spring 框架中提供 BeanUtils.copyProperties(source,target); 这里我们演示第一种

//需实现Cloneable接口
public class Person implements Cloneable {int num;String name;public Person() { }public Person(int num, String name) {this.num = num;this.name = name;}//重写Object中的clone()方法, 实现克隆@Overrideprotected Person clone() throws CloneNotSupportedException {Person person = (Person) super.clone();return person;}
}
public static void main(String[] args) throws CloneNotSupportedException {Person p1 = new Person(100,"jim");Person p2 = p1.clone(); //调用克隆方法System.out.println(p1==p2);}

以上输出结果当然为 false , 因为克隆后虽然包含数据相同, 但仍旧是两个对象, 采用 == 的方式比较,  输出的是两个对象的引用地址是否相同 , 当然为 false

当然在这里肯定有人会提出这样一个问题 : String不是引用类型吗? 怎么值跟着复制了

首先我们回想String的特点, 引用类型没错, 但是String底层的char数组是采用了 final修饰的,  被final修饰的我们叫做常量, 也就是不可改变的, 所以说 , String虽然是引用类型, 但是它的值一旦确定就不能再改变了, 所以值会跟着复制

深克隆

深克隆会将引用类型所指向对象中包含的数据一同复制, 这里也需实现Cloneable接口

先设计一个Address类

//实现Cloneable接口
public class Address  implements Cloneable{String  address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "Address{" +"address='" + address + '\'' +'}';}// 重写clone()方法@Overrideprotected Address clone() throws CloneNotSupportedException {return (Address)super.clone(); }
}

接着是person类

//实现Cloneable接口
public class Person implements  Cloneable{int num;String name;//在Person中关联Address对象Address address;public Person() {}public Person(int num, String name) {this.num = num;this.name = name;}// 由于会导致篇幅过长, 此处省略属性的get和set方法//重写clone()方法实现深度克隆@Overrideprotected Person clone() throws CloneNotSupportedException {Person person = (Person)super.clone();//深度复制  联同person中关联的对象也一同克隆person.address = (Address)address.clone();return person;}@Overridepublic String toString() {return "Person{" +"num=" + num +", name='" + name + '\'' +", address=" + address +'}';}
}

test类

public class Test {public static void main(String[] args) throws CloneNotSupportedException {//先new一个Address类对象并设置值Address address = new Address();address.setAddress("成都");// new 一个Person类对象并设置值(将address属性加入)Person p1 = new  Person(100,"jim");p1.setAddress(address);//克隆Person p2 =p1.clone();p2.setName("tom");//改变address所指向对象的值,如果深克隆成功,这个值即使改变也影响不了p2address.setAddress("西安");System.out.println("p1:"+p1);System.out.println("p2:"+p2);/** 结果 : p1:Person{num=100, name='jim', address=Address{address='西安'}}*       p2:Person{num=100, name='tom', address=Address{address='成都'}}*       深克隆成功* */}
}

这就是深克隆, 连同引用对象中包含的值一起复制, 在上述例子中 , 如果是浅克隆, 仅仅复制了引用, 引用一旦发生改变, 原对象和克隆的对象中的address属性都会发生改变(如果浅克隆上述例子p1和p2中的address都会为"西安")

多层克隆

了解了深克隆, 那么有人会想到, 如果对象中套对象, 对象中再套对象, 这样一直连环套该怎样解决呢 ?

最为简单粗暴的一种方式就是 : 手动一层一层克隆, 这样当然也可以, 但是这里我们介绍一种更为简便的方式 : 序列化   , 当然简单的深克隆也是可以去使用序列化这种方式的

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable 接口,否则无法实现序列化操作。

Address类

//实现Serializable接口
public class Address  implements Serializable {String  address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "Address{" +"address='" + address + '\'' +'}';}
}

Person类

//实现Serializable接口
public class Person implements Serializable {int num;String name;Address address;public Person() {}public Person(int num, String name) {this.num = num;this.name = name;}//省略get和set方法//自定义克隆方法public Person myclone() {Person person = 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);person = (Person) ois.readObject();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return person;}@Overridepublic String toString() {return "Person{" +"num=" + num +", name='" + name + '\'' +", address=" + address +'}';}
}

测试不变, 不过这里我们克隆使用的是自己定义的myClone()方法 ,使用流的方式完成

关于对象克隆就说到这里, 感谢阅读.

Java - 对象克隆相关推荐

  1. java对象克隆的例子_Java对象克隆

    本篇文章帮大家学习java对象克隆,包含了Java对象克隆使用方法.操作技巧.实例演示和注意事项,有一定的学习价值,大家可以用来参考. Java不提供克隆(复制)对象的自动机制.克隆对象意味着逐位复制 ...

  2. java对象克隆效率_fastclone

    fastclone 一款轻量级Java对象高效克隆框架,提供高性能的深克隆(非Object->序列化->Object这种低效率克隆).浅克隆,支持递归克隆.性能上秒杀Apache Comm ...

  3. Java对象克隆方法(浅克隆、深克隆)

    要让一个对象进行克隆,其实就是两个步骤: 1. 让该类实现java.lang.Cloneable接口: 2. 重写(override)Object类的clone()方法. 上面的克隆方法其实是浅克隆, ...

  4. Java对象克隆——浅克隆和深克隆的区别

    在Java中对象的克隆有深克隆和浅克隆之分.有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的.基本数据类型存储在栈中,引用数据类型存储在堆中. ...

  5. java对象克隆详解

    概述: 当我们new一个对象时,其中的属性就会被初始化, 那么想要保存刚开始初始化的值就靠clone方法来实现, 平时我们最常见的是一个对象的引用指向另一个对象,并不是创建了两个对象. Person ...

  6. java 对象克隆_JAVA对象克隆

    1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法. 2> 在派生类中覆盖基类的clone(),并声明为public. 3> 在派生类的clone()方法中 ...

  7. java 克隆_Java实现对象克隆的方法

    前言 这也是昨天的面试题. 当时只说了深拷贝以及浅拷贝,面试官问了两遍还有吗,我很肯定的说就这两种了,面试结束之后查了一下,啪啪打脸. 正文 JAVA实现克隆有两种形式 浅克隆 深克隆 浅克隆与深克隆 ...

  8. java序列化深克隆_克隆可序列化和不可序列化的Java对象

    java序列化深克隆 开发人员经常依靠3d方库来避免重新发明轮子,尤其是在Java世界中,Apache和Spring这样的项目如此盛行. 在处理这些框架时,我们通常很少或根本无法控制其类的行为. 这有 ...

  9. 克隆可序列化和不可序列化的Java对象

    开发人员经常依靠3d方库来避免重新发明轮子,尤其是在Java世界中,Apache和Spring这样的项目如此盛行. 在处理这些框架时,我们通常很少或根本无法控制其类的行为. 这有时会导致问题. 例如, ...

最新文章

  1. MikroTik RouterOS获取在线终端和在线IP总数并自动对IP做限速(转)
  2. c++学习笔记之数组及vector
  3. cpu高对计算机有什么影响吗,CPU损坏对电脑造成哪些影响
  4. linux 修复图形界面,图形界面操作的备份和恢复Linux发行版
  5. 内存小还免费,Adobe Acrobat表示有危机
  6. 七、Forword(请求转发)与Redirect(重定向)
  7. Python - 浅谈Python的编译与反编译
  8. 又一自动驾驶独角兽诞生!Momenta获2亿美元总融资,腾讯首投中国无人车
  9. Laravel 大将之 路由 模块
  10. CISA 称SolarWinds黑客或通过密码猜测攻陷目标,CISA 前局长受聘
  11. 测试开发字节跳动(二面),我被面试官按在地上摩擦!
  12. 如何提高Eclipse的运行速度 之总结
  13. 《我也能做CTO之程序员职业规划》之四:直线定律
  14. Winform 五种常用对话框控件的简单使用
  15. WORD中的表格如何快捷键添加一行
  16. 阿里巴巴国际站组合标题的小技巧
  17. Flowable入门系列文章39 - 网关 01
  18. 家庭mesh组网方案
  19. Ubuntu快速下载电驴ed2k文件
  20. 南京润和,哎,感概!

热门文章

  1. 软件设计之UML—UML的构成[上]
  2. 华硕笔记本U盘装系统教程
  3. 车载电子电器做E-mark认证的费用是多少?
  4. 常用MIME类型(Mp4的mime类型设置)
  5. C++实验题8 数组使用(bushi)
  6. bugku-web-source
  7. 2017年清华大学计算机科学与技术系考研小结
  8. 将java对象存储到redis数据库(两种实现方式)
  9. 【Java】interrupt、interrupted和isInterrupted的区别
  10. C语言解决百钱百鸡问题