浅拷贝-深拷贝总结
浅拷贝:
基本数据类型 | 引用数据类型 |
---|---|
值传递 | 成员变量的引用值(内存地址)复制(实际指向同一个) |
深拷贝:
基本数据类型 | 引用数据类型 |
---|---|
值传递 | new一个新对象,进行属性赋值 |
浅拷贝两种实现方法
1、拷贝构造函数
一个学生类,包含两个属性,一个是基本数据类型name,一个是引用数据类型Age
public class Boy {
String name;
Age age;
public Boy() {
}
public Boy(String name, Age age) {
this.name = name;
this.age = age;
}
//拷贝构造函数,实现了对象的拷贝,基本数据类型值传递,引用数据类型内存地址复制
public Boy(Boy b){
this.age = b.age;
this.name = b.name;
}
public Age getAge() {
return age;
}
public void setAge(Age age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Boy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Age{
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Age(int age) {
this.age = age;
}
@Override
public String toString() {
return "Age{" +
"age=" + age +
'}';
}
}
public class Copyconstructor {
public static void main(String[] args) {
Age age = new Age(26);
Boy boy = new Boy("pmh",age);
//通过拷贝构造函数实现了对象的浅拷贝
Boy boy1 = new Boy(boy);
//我们通过修改其中一个去判断
boy.name = "zyf";
age.setAge(99);
System.out.println(boy);
System.out.println(boy1);
}
}
结果
Boy{name='zyf', age=Age{age=99}}
Boy{name='pmh', age=Age{age=99}}
2、重写clone()方法进行浅拷贝
注意点:
1、protected native Object clone() throws CloneNotSupportedException;权限是受保护的,我们无法直接使用
2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException
步骤如下
1、对象如果想通过clone方法实现浅拷贝,首先需要实现cloneable接口,重写clone()方法
public class Student implements Cloneable {
String name;
Score score;
public Student(String name, Score score) {
this.name = name;
this.score = score;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Score getScore() {
return score;
}
public void setScore(Score score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Score{
int score;
public Score(int score) {
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Score{" +
"score=" + score +
'}';
}
}
public class CopyCloneable {
public static void main(String[] args) {
Score score = new Score(100);
Student student = new Student("pmh",score);
try {
//由此我们通过实现了Cloneabe的实现类Student重写的clone方法实现了浅拷贝
Student student1 = (Student)student.clone();
System.out.println(student);
System.out.println(student1);
student.name = "ZYhf";
score.score = 99;
System.out.println(student);
System.out.println(student1);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
结果
Student{name='pmh', score=Score{score=100}}
Student{name='pmh', score=Score{score=100}}
Student{name='ZYhf', score=Score{score=99}}
Student{name='pmh', score=Score{score=99}}
深拷贝两种实现方法
1、重写clone方法来实现深拷贝
1、假设Student有两个属性,一个基本数据类型name,一个引用数据类型Socre,我们首先需要让Score实现cloneable接口,重写方法clone()
class Score implements Cloneable{
int score;
public Score(int score) {
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Score{" +
"score=" + score +
'}';
}
@Override
protected Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
2、然后让Student实现cloneable接口,实现clone方法,通过获取拷贝的Student实例的Score属性重新进行一次拷贝
public class Student implements Cloneable {
String name;
Score score;
public Student(String name, Score score) {
this.name = name;
this.score = score;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Score getScore() {
return score;
}
public void setScore(Score score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
@Override
protected Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
Student stu = (Student) obj;
stu.score= (Score) stu.getScore().clone();
return obj;
}
}
结果
Student{name='pmh', score=Score{score=100}}
Student{name='pmh', score=Score{score=100}}
Student{name='ZYhf', score=Score{score=99}}
Student{name='pmh', score=Score{score=100}}
虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
2、通过对象序列化实现深拷贝
class Hobby implements Serializable{
private String hobby;
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Hobby(String hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "Hobby{" +
"hobby='" + hobby + '\'' +
'}';
}
}
public class Girl implements Serializable{
private String name;
private Hobby hobby;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Hobby getHobby() {
return hobby;
}
public void setHobby(Hobby hobby) {
this.hobby = hobby;
}
public Girl(String name, Hobby hobby) {
this.name = name;
this.hobby = hobby;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
", hobby=" + hobby +
'}';
}
}
public class CopyWithSerializable {
public static void main(String[] args) throws Exception {
Hobby hobby = new Hobby("乒乓球");
Girl girl1 = new Girl("pmh",hobby);
//通过序列化方法实现深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(girl1);
oos.flush();
ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Girl girl2=(Girl)ois.readObject();
System.out.println(girl1.toString());
System.out.println(girl2.toString());
System.out.println();
//尝试修改stu1中的各属性,观察stu2的属性有没有变化
girl1.setName("大傻子");
//改变age这个引用类型的成员变量的值
hobby.setHobby("羽毛器");
girl1.setName("216");
System.out.println(girl1.toString());
System.out.println(girl2.toString());
}
}
结果
Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}
Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}
Girl{name='216', hobby=Hobby{hobby='羽毛器'}}
Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}