网站首页 > java教程 正文
关于深克隆和浅克隆:
根据结果,克隆分两种:(对于基本数据类型的属性,不考虑深或者浅拷贝)
- 深克隆:引用类型属性也克隆
- 浅克隆:引用类型属性不克隆
对象实现克隆的必要条件
对于clone()方法:要使对象实现克隆,需要让对象实体类实现Cloneable接口(它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常)。
clone() 是 Object 方法,通过该方法克隆一个一模一样的对象。一般通过实现 cloneable 接口实现该方法,在 Object 类中该方法是 native 方法,基于底层操作系统实现。
// 具体使用
A a1 = new A();
A a2 = (A)a1.clone();
当我们调用 clone() 方法后,首先根据原对象的大小申请内存空间,申请完内存空间后,将原对象内存域复制到新申请的内存空间,返回引用类型。也就是说,从内存地址来看,clone() 会创建一个全新的对象。
但是实际上此方法实现的是浅拷贝
String特殊性: 因为他为引用型,而且他指向的值为常量,克隆出来的对象改变他的值。实际上是改变了克隆出来对象String类型成员的指向,不会影响被克隆对象的值及其指向。因为执行 cloned.name = "new";语句时,它作用相当于生成了一个新的string类型,然后又赋回给cloned.name。
如何用clone()方法实现深拷贝:
现在为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。
使用该方式实现深克隆,需要注意以下几点:
- 被克隆的类必须实现 Cloneable 接口。
- 所有子对象也必须实现 Cloneable 接口,否则会抛出 CloneNotSupportedException 异常。
- 所有子对象的 clone() 方法必须调用 super.clone() 并将其结果强制转换为子对象类型。
- 所有子对象的 clone() 方法中,如果子对象包含其他子对象,需要递归调用其 clone() 方法以实现深克隆。
- 如果被克隆的类和子对象包含不可变对象,则可以不用复制其副本,以提高性能。
如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone(); //重写clone()方法,并对引用类型进行克隆
return newBody;
}
}
static class Head implements Cloneable{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
打印结果为:
body == body1 : false //对象引用不一
body.head == body1.head : false //对象属性的应用也不一样
由此可见, body和body1内的head引用指向了不同的Head对象, 也就是说在clone Body对象的同时, 也拷贝了它所引用的Head对象, 进行了深拷贝。
存在问题:对于Head的中的引用类型属性Face来说,Body是没有进行深拷贝的
那么如何实现真正的深拷贝:如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝
BeanUtils工具类中的copyProperties方法是深拷贝还是浅拷贝:浅拷贝
猜你喜欢
- 2024-10-19 Python 中赋值、浅拷贝、深拷贝的区别是什么?
- 2024-10-19 Java 对象拷贝原理剖析(java 对象拷贝原理剖析)
- 2024-10-19 认识Object类和深浅拷贝!(阐述object.assign的用法,深拷贝与浅拷贝的区别?)
- 2024-10-19 三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
- 2024-10-19 谈谈 Java 开发中的对象拷贝(java对象拷贝工具类)
- 2024-10-19 深入浅出Java中的clone克隆方法,写得也太棒了
- 2024-10-19 深拷贝和浅拷贝之list、dataframe
- 2024-10-19 对象拷贝java 浅谈(java对象的拷贝)
- 2024-10-19 Java克隆对象需要知道的事(java克隆的作用)
- 2024-10-19 Java的Object十二个常用方法,你用过几个?
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)