一、浅复制和深复制概念

浅复制(浅克隆): 被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不是复制它所引用的对象。

深复制(深克隆): 被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象, 而不再试原有的那些被引用的对象。换言之,深复制把复制的对象所应用的对象都复制了一遍。

二、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)的更多相关文章

  1. 深拷贝(deep clone)与浅拷贝(shallow clone)

    深拷贝(deep clone)与浅拷贝(shallow clone) 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复 ...

  2. java的clone()、浅拷贝与深拷贝

    clone()方法是Object的native方法.protected native Object clone() throws CloneNotSupportedException;  声明为pro ...

  3. Java:浅克隆(shallow clone)与深克隆(deep clone)

    Summary 浅克隆与深克隆对于JavaSE来说,是个难度系数比较低的概念,但不应该轻视它. 假设一个场景:对于某个list,代码里并没有任何对其的直接操作,但里面的元素的属性却被改变了,这可能就涉 ...

  4. 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考

    首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME    copy - Generic (shallow and dee ...

  5. copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)

    写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...

  6. shallow clone

    shallow clone 浅克隆经常在一些大型仓库中很有用——不用花费大量时间去clone一个完整的仓库,仅仅checkout出来某个分支(如master)的最新N次递交: git clone -- ...

  7. Java中的深拷贝(深复制)和浅拷贝(浅复制)

    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...

  8. git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

    git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

  9. 浅谈浅克隆(shallow clone)和 深克隆(deep clone)

    区别就在于是否对对象中的引用变量所指向的对象进行拷贝. 1.浅克隆/浅复制/浅拷贝 浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,没有对引用指向 ...

随机推荐

  1. Python学习日记(十四) 正则表达式和re模块

    正则表达式: 它是字符串的一种匹配模式,用来处理字符串,可以极大地减轻处理一些复杂字符串的代码量 字符组:它是在同一位置可能出现的各种字符组成了一个字符组,用[]表示,但是它的结果只能是一个数字或者一 ...

  2. WebService接口学习【1】

    工具: 1.Eclipse(or)IDEA编辑器 2.SoapUI测试工具 1.wsdl文件标签体的约束: 一:namespace:相当于文件的id 二:targetNamespace属性:用来指定s ...

  3. 关于类型为numpy,TensorFlow.tensor,torch.tensor的shape变化以及相互转化

    https://blog.csdn.net/zz2230633069/article/details/82669546 2018年09月12日 22:56:50 一只tobey 阅读数:727   1 ...

  4. git修改提交历史中的author信息

    当次提交 当次的提交显示指定提交者信息: git commit -m "Initial commit" --author="mn <mn@furzoom.com&g ...

  5. 【Low版】HAUT - OJ - Contest1035 - 2017届新生周赛(六)题解

    问题 A: 比赛 时间限制: 2 秒 内存限制: 256 MB | 提交: 393 解决: 98提交 状态 题目描述 学校要派6名同学组成两个队(一个队3个人)去参加比赛,每个同学有一个分数,学校希望 ...

  6. grep命令的or,and,not操作的例子

    在Linux的grep命令中如何使用OR,AND,NOT操作符呢? 其实,在grep命令中,有OR和NOT操作符的等价选项,但是并没有grep AND这种操作符.不过呢,可以使用patterns来模拟 ...

  7. zmq使用记录

    zmq套接字介绍 https://www.cnblogs.com/fengbohello/p/4354989.html zmq示例 https://github.com/booksbyus/zguid ...

  8. com.alibaba.fastjson把JSONObject转换为Map<String, String>对象

    https://www.cnblogs.com/fomeiherz/p/6351287.html JSONObject obj = new JSONObject();{obj.put("ke ...

  9. Django 第一天 开端

    今日内容: 一.HTTP协议 1.HTTP协议简介 参考博客:https://www.cnblogs.com/clschao/articles/9230431.html 是超文本传输协议 现在使用最广 ...

  10. Acwing P284 金字塔 题解

    Analysis 一棵树的每颗子树都对应着这棵树 DFS 序的一个区间.本题的序列虽然不是 DFS 序列,但也有该性质.本题中,我们以区间长度作为阶段, F[ l , r ] 表示序列 s[ l ~ ...