浅拷贝定义:
-
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
-
简而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象
深拷贝定义:
-
深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
-
简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
"=" 的作用:
-
基本类型:拷贝数据的值
-
其他类型:拷贝地址的引用,拷贝出的新对象与原对象共享实例变量,不受访问权限影响。
-
String 类型:拷贝的也是一个引用,但其内容存储在字符串池中,修改会重新生成新的字符串,原有字符串内容是保持不变的(String 是不可变的),等同于基本类型。
浅拷贝
浅拷贝就是直接使用 "=" 给基本类型赋值(即拷贝引用)。
List<String> srcList = new ArrayList<>();
srcList.add("android");
List<String> cpyList = srcList;
srcList.add("ios");
- 输出这两个list,srcList和cpyList都有android,ios两项。
深拷贝
深拷贝就是将所有属性均拷贝到另外一个对象中,将其中任何一个对象任何一个属性发生变化时,另外一个对象不受任何影响。
List<String> srcList = new ArrayList<>();
srcList.add("android");
List<String> cpyList = new ArrayList<>(srcList);
srcList.add("ios");
- 输出这两个list,srcList有android,ios两项,而cpyList只有android一项。
深拷贝实现
(1)clone 实现深拷贝
每个对象都是继承于 Object 类,Object 类提供了 clone()
方法,通过实现 Cloneable
接口可以使该具有拷贝的能力,拷贝的操作是在内存中进行的,所以性能会比直接构造对象要快速很多。
public class DeepCopyByClone {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Yao");
s1.setTeacher(new Teacher("Kobe"));
Student s2 = s1.clone();
s2.setName("Yi");
s2.getTeacher().setName("Jordan");
System.out.println(s1.getName() + "'s teacher is "
+ s1.getTeacher().getName());
System.out.println(s2.getName() + "'s teacher is "
+ s2.getTeacher().getName());
}
}
class Student implements Cloneable {
private String name;
private Teacher teacher;
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
protected Student clone() {
Student student = null;
try {
student = (Student) super.clone();
student.setTeacher(student.getTeacher());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
}
class Teacher {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher(String name) {
this.name = name;
}
}
- 输出
Yao's teacher is Jordan
Yi's teacher is Jordan
- 图片分析
这里关于teacher的拷贝是通过=
号来操作的,仅仅实现了浅拷贝。以下的 clone()
方法的修改将实现深拷贝。
@Override
protected Student clone() {
Student student = null;
try {
student = (Student) super.clone();
//student.setTeacher(student.getTeacher());
student.setTeacher(new Teacher(student.getTeacher().getName()));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
- 输出
Yao's teacher is Kobe
Yi's teacher is Jordan
- 图片分析
(2)对象序列化实现深拷贝
通过对象序列化,使用 writeObject
和 readObject
也可以实现对象的深拷贝。
把对象写到流里的过程是序列化过程(Serialization),而把对象从流中读出来的过程则叫做反序列化过程(Deserialization)。
应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
import java.io.*;
public class CloneUtils {
@SuppressWarnings("unchecked")
public static Object clone(Object obj) {
Object cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
public static void main(String[] args) {
Student2 s1 = new Student2();
s1.setName("Yao");
s1.setTeacher(new Teacher2("Kobe"));
Student2 s2 = (Student2) CloneUtils.clone(s1);
s2.setName("Yi");
s2.getTeacher().setName("Jordan");
System.out.println(s1.getName() + "'s teacher is "
+ s1.getTeacher().getName());
System.out.println(s2.getName() + "'s teacher is "
+ s2.getTeacher().getName());
}
}
class Student2 implements Serializable {
private String name;
private Teacher2 teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher2 getTeacher() {
return teacher;
}
public void setTeacher(Teacher2 teacher) {
this.teacher = teacher;
}
}
class Teacher2 implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher2(String name) {
this.name = name;
}
}
参考文章:
网友评论