深拷贝(deep clone)与浅拷贝(shallow clone)
一、浅复制和深复制概念
浅复制(浅克隆): 被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不是复制它所引用的对象。
深复制(深克隆): 被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象, 而不再试原有的那些被引用的对象。换言之,深复制把复制的对象所应用的对象都复制了一遍。
二、Java的Clone()方法 【定义在Object类中】
clone方法将对象复制一份并返回给调用者。
一般而言,clone() 方法满足:
1、对任何对象x,都有x.clone() != x
克隆对象与原对象不是一个对象
2、对任何的对象x,都有
x.clone().getClass() == x.getClass()
克隆对象与原对象的类型一样
3、如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立
二、浅复制Demo
public class CloneTest1 { public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student();
student.setAge(20);
student.setName("Larry"); Student student2 = (Student)student.clone();
System.out.println(student2.getAge());
System.out.println(student2.getName()); System.out.println("-----------------------"); student2.setName("Nick");
System.out.println(student.getName());
System.out.println(student2.getName()); }
} class Student implements Cloneable{
private int age;
private String name;
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;
} @Override
public Object clone() throws CloneNotSupportedException {
Object object = super.clone();
return object;
}
}
打印结果
20
zhangsan
-----------------------
zhangsan
Lisi
student2.setName("Nick"); 执行后,student2的name赋予新的值,指向新的空间。如下图
三、深复制
以下代码还是浅复制
public class CloneTest2 { public static void main(String[] args) throws CloneNotSupportedException { Teacher teacher = new Teacher();
teacher.setAge(40);
teacher.setName("Teacher zhang"); Student2 s1 = new Student2();
s1.setAge(20);
s1.setName("zhangsan");
s1.setTeacher(teacher); Student2 s2 = (Student2)s1.clone();
System.out.println(s2.getAge());
System.out.println(s2.getName()); teacher.setName("Teacher Li"); System.out.println(s2.getTeacher().getAge());
System.out.println(s2.getTeacher().getName()); }
} class Teacher {
private int age;
private String name; 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;
} } class Student2 implements Cloneable{
private int age;
private String name; private Teacher teacher; 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;
} public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
Object object = super.clone();
return object;
}
}
修改成深复制
Teacher也实现Clone方法
然后改写Student的Clone方法
clone Student的时候,修改Teacher。
修改后的完整代码:
public class CloneTest2 { public static void main(String[] args) throws CloneNotSupportedException { Teacher teacher = new Teacher();
teacher.setAge(40);
teacher.setName("Teacher zhang"); Student2 s1 = new Student2();
s1.setAge(20);
s1.setName("zhangsan");
s1.setTeacher(teacher); Student2 s2 = (Student2)s1.clone();
System.out.println(s2.getAge());
System.out.println(s2.getName()); teacher.setName("Teacher Li"); System.out.println(s2.getTeacher().getAge());
System.out.println(s2.getTeacher().getName()); }
} class Teacher implements Cloneable{
private int age;
private String name; 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;
} @Override
public Object clone() throws CloneNotSupportedException { return super.clone();
} } class Student2 implements Cloneable{
private int age;
private String name; private Teacher teacher; 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;
} public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
Student2 student2 = (Student2)super.clone();
student2.setTeacher((Teacher)student2.getTeacher().clone());
return student2;
}
}
五、利用序列化来做深复制(最简单也是最多的一种方式)
1、使用Clone方法实现深复制存在的缺点: 存在多个引用的成员变量,将做多次处理。
如上图做了一次处理,如果有多个应用,将做多次处理。
2、序列化/反序列化
把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读取出来的过程则叫饭序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面
1)在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
2)这样做的前提示对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否设成transient,从而将之排除在复制过程之外。
3)Code
public class CloneTest3 { public static void main(String[] args) throws Exception { Teacher3 teacher = new Teacher3();
teacher.setAge(40);
teacher.setName("Teacher zhang"); Student3 s1 = new Student3();
s1.setAge(20);
s1.setName("zhangsan");
s1.setTeacher(teacher); Student3 s2 = (Student3)s1.deepCopy();
System.out.println(s2.getAge());
System.out.println(s2.getName());
System.out.println("-------------"); System.out.println(s2.getTeacher().getAge());
System.out.println(s2.getTeacher().getName()); s2.getTeacher().setAge(50);
s2.getTeacher().setName("Teacher Li"); System.out.println(s1.getTeacher().getAge());
System.out.println(s1.getTeacher().getName()); }
} class Teacher3 implements Serializable{ //private static final long serialVersionUID = 675697793444541314L;
private int age;
private String name; 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;
} } class Student3 implements Serializable{ //private static final long serialVersionUID = -7008294898863009451L;
private int age;
private String name; private Teacher3 teacher; 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;
} public Teacher3 getTeacher() {
return teacher;
}
public void setTeacher(Teacher3 teacher) {
this.teacher = teacher;
} 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();
} }
打印结果:
20
zhangsan
-------------
40
Teacher zhang
40
Teacher zhang
六、关于实现Seriallizable接口的类中的serialVersionUID问题
如果你的对象序列化后存在硬盘上面后,可是后来你更改了类的field(增加或减少或改名),当你反序列化时,就会出现Execption的,这样就会造成不兼容性的问题。
但当serialVersionUID相同时,它就会将不一样的field以type的缺省值Deserialize,这样可以避开不兼容的问题。
深拷贝(deep clone)与浅拷贝(shallow clone)的更多相关文章
- 深拷贝(deep clone)与浅拷贝(shallow clone)
深拷贝(deep clone)与浅拷贝(shallow clone) 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复 ...
- java的clone()、浅拷贝与深拷贝
clone()方法是Object的native方法.protected native Object clone() throws CloneNotSupportedException; 声明为pro ...
- Java:浅克隆(shallow clone)与深克隆(deep clone)
Summary 浅克隆与深克隆对于JavaSE来说,是个难度系数比较低的概念,但不应该轻视它. 假设一个场景:对于某个list,代码里并没有任何对其的直接操作,但里面的元素的属性却被改变了,这可能就涉 ...
- 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考
首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME copy - Generic (shallow and dee ...
- copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)
写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...
- shallow clone
shallow clone 浅克隆经常在一些大型仓库中很有用——不用花费大量时间去clone一个完整的仓库,仅仅checkout出来某个分支(如master)的最新N次递交: git clone -- ...
- Java中的深拷贝(深复制)和浅拷贝(浅复制)
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...
- git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug
git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug
- 浅谈浅克隆(shallow clone)和 深克隆(deep clone)
区别就在于是否对对象中的引用变量所指向的对象进行拷贝. 1.浅克隆/浅复制/浅拷贝 浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,没有对引用指向 ...
随机推荐
- 关于在centos下安装python3.7.0以上版本时报错ModuleNotFoundError: No module named '_ctypes'的解决办法
3.7版本需要一个新的包libffi-devel,安装此包之后再次进行编译安装即可. #yum install libffi-devel -y#make install若在安装前移除了/usr/bin ...
- Java8 stream用法-备忘录
1. 如何使用匹配模式 List<String> strs = Arrays.asList("a", "a", "a", &qu ...
- ISCC之web2
Php代码审计 PHP代码 <?php error_reporting(0); require 'flag.php'; $value = $_GET['value']; $password = ...
- STL详细介绍(更新中~~~)
目录 string string的常见构造函数 string与char *(或const char*)之间的转换 string 转化为const char* const char* 转化为string ...
- Nginx中获取真实ip地址
location / { proxy_pass http://localhost; proxy_set_header Host $host; proxy_set_header X-Real-IP $r ...
- Java&Selenium自动化测试之Page Object Model
PO是什么: 1.页面对象模型(PO)是一种设计模式,用来管理维护一组web元素的对象库 2.在PO下,应用程序的每一个页面都有一个对应的page class 3.每一个page class维护着该w ...
- szwyadmin程序漏洞拿shell【方法笔记】
我们在Google中搜索关键词 关键字:inurl:szwyadmin/login.asp 任意打开一个搜索结果,打开登录界面后在地址栏中输入下面的代码: 代码: javascript:alert(d ...
- LSTM神经网络输入输出究竟是怎样的?
LSTM图和词向量输入分析
- docker的笔记
docker run 命令 docker run ubuntu:15.10 /bin/echo "Hello world" 各个参数解析: docker: Docker 的二进制执 ...
- 指数基金介绍专栏(8):国企指数(H股指数)详细介绍,最新资料解析,看这一篇就够了
作者:牛大 | 公众号:定投五分钟 大家好,我是牛大.每天五分钟,投资你自己:坚持基金定投,终会财富自由! 昨天牛大给大家介绍了恒生指数,没看的朋友可以去公众号看一下. 指数基金介绍专栏(7):恒生指 ...