简介

        本文介绍Java中的浅拷贝和深拷贝的使用。

        浅拷贝(Shallow Copy),深拷贝(Deap Copy)。

浅拷贝(Shallow Copy)

简介

对基本数据类型进行值复制(修改一个对象的变量值,不会影响另一个对象的数据)

对引用数据类型(对象、数组)进行引用地址的复制(修改一个对象的变量值,会影响另一个对象的数据)

String:虽然是引用数据类型,但因为它的不可变性,修改clone后的值并不会影响到原先的值。

示例

package org.example.a;

class Subject {
String name; //String引用类型
int classNum; //基本数据类型

public Subject(String name, int classNum) {
this.name = name;
this.classNum = classNum;
}

@Override
public String toString() {
return "Subject{" +
"name='" + name + '\'' +
", classNum=" + classNum +
'}';
}
}

class School implements Cloneable {
int age; //基本数据类型
String name; //String引用类型
Subject subject; //类的对象,引用类型

// 由于 Object 本身没有实现 Cloneable 接口
// 所以不重写 clone 方法并且进行调用的话会发生 CloneNotSupportedException 异常。
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "School{" +
"age=" + age +
", name='" + name + '\'' +
", subject=" + subject +
'}';
}
}


public class Demo {
public static void main(String[] args) {
School school1 = new School();
school1.age = 1;
school1.name = "One";
school1.subject = new Subject("Java", 1024);
System.out.println("原先的school1:" + school1);

School school2 = null;
try {
school2 = (School) school1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return;
}
System.out.println("原先的school2:" + school2);

school2.age = 2; //改变clone后的age
school2.name = "Two"; //改变clone后的name
school2.subject.name = "New"; //改变clone后的subject对象的name
school2.subject.classNum = 1025; //改变clone后的subject对象的name
System.out.println("修改后的school1:" + school1);
System.out.println("修改后的school2:" + school2);
}
}

执行结果(​基本类型和String类型互不影响,对象类型相互影响​

原先的school1:School{age=1, name='One', subject=Subject{name='Java', classNum=1024}}
原先的school2:School{age=1, name='One', subject=Subject{name='Java', classNum=1024}}
修改后的school1:School{age=1, name='One', subject=Subject{name='New', classNum=1025}}
修改后的school2:School{age=2, name='Two', subject=Subject{name='New', classNum=1025}}

深拷贝(Deap Copy)

简介

对基本数据类型:值复制(修改一个对象的变量值,不会影响另一个对象的数据)

对引用数据类型(对象、数组):创建新对象,并复制其内容(修改一个对象的变量值,不会影响另一个对象的数据)

方案1:对引用类型的字段也进行克隆

package org.example.a;

class Subject implements Cloneable{
String name; //String引用类型
int classNum; //基本数据类型

public Subject(String name, int classNum) {
this.name = name;
this.classNum = classNum;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "Subject{" +
"name='" + name + '\'' +
", classNum=" + classNum +
'}';
}
}

class School implements Cloneable {
int age; //基本数据类型
String name; //String引用类型
Subject subject; //类的对象,引用类型

// 深拷贝,循环写clone
@Override
protected Object clone() throws CloneNotSupportedException {
School deepSchool = null;
try {
deepSchool = (School) super.clone();
deepSchool.subject = (Subject) deepSchool.subject.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
return deepSchool;
}

@Override
public String toString() {
return "School{" +
"age=" + age +
", name='" + name + '\'' +
", subject=" + subject +
'}';
}
}


public class Demo {
public static void main(String[] args) {
School school1 = new School();
school1.age = 1;
school1.name = "One";
school1.subject = new Subject("Java", 1024);
System.out.println("原先的school1:" + school1);

School school2 = null;
try {
school2 = (School) school1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return;
}
System.out.println("原先的school2:" + school2);

school2.age = 2; //改变clone后的age
school2.name = "Two"; //改变clone后的name
school2.subject.name = "New"; //改变clone后的subject对象的name
school2.subject.classNum = 1025; //改变clone后的subject对象的name
System.out.println("修改后的school1:" + school1);
System.out.println("修改后的school2:" + school2);
}
}

执行结果(​所有数据都互不影响​

原先的school1:School{age=1, name='One', subject=Subject{name='Java', classNum=1024}}
原先的school2:School{age=1, name='One', subject=Subject{name='Java', classNum=1024}}
修改后的school1:School{age=1, name='One', subject=Subject{name='Java', classNum=1024}}
修改后的school2:School{age=2, name='Two', subject=Subject{name='New', classNum=1025}}

方案2:序列化(不推荐)

  1. 序列化(serialization)这个对象,再反序列化回来,就可以得到这个新的对象,无非就是序列化的规则需要我们自己来写。

其他网址


​Java深拷贝和浅拷贝​