本文对浅克隆和深克隆的两种方法(不引入别的开源工具)进行了简单的代码实现(没有内部类语法),对比了浅克隆和深克隆对引用类型的影响,暂不考虑不可变类,确保初学Java者能够看懂并学会,可直接复制源代码进行使用和测试
目录
第一种方法:重写clone方法,对每一个引用类型再进行clone
2.重写Pet类里的clone方法,把Dog和Cat引用类型再分别进行clone
1.准备好Cat、Dog、Pet三个类,三个类都实现Serializable接口
2.创建一个SerializableCloneTest的类,进行序列化和反序列并且测试深克隆效果
前言:为什么要克隆
对象克隆是指以现有对象为基础,克隆出一个和它完全相同的对象
为什么要进行克隆,直接new一个对象不好吗?
因为克隆的速度快于new对象的速度
一、关于克隆的概述
Java中的克隆分为深克隆和浅克隆
浅克隆:将基本类型复制,但是对引用类型则只复制地址,浅克隆后引用类型地址相同;
深克隆:是将对象中的基本类型复制,将引用类型所指向的对象也进行复制,深克隆后引用类型地址不同,克隆后成为真正独立的个体;
二、浅克隆的代码实现
1.创建一个Cat类
增加get和set方法,带参构造器,重写toString
public class Cat {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.同样,再创建一个Dog类
public class Dog {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.创建一个Pet类,重写clone方法
public class Pet implements Cloneable {//创建一个宠物类,实现Cloneable接口
private int quantity;
private Dog dog;//创建一个Dog引用类型
private Cat cat;//创建一个Cat引用类型
public Pet(int quantity, Dog dog, Cat cat) {
this.quantity = quantity;
this.dog = dog;
this.cat = cat;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Pet{" +
"quantity=" + quantity +
", dog=" + dog +
", cat=" + cat +
'}';
}
@Override
public Pet clone() throws CloneNotSupportedException {
//此处改为public Pet是方便后续创建的CloneTest类中的对象好调用clone()
Pet clonePet = (Pet) super.clone();
return clonePet;
}
}
4.创建一个CloneTest类来测试浅克隆效果
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog("Spike", 10);
Cat cat = new Cat("Tom", 12);
Pet pet = new Pet(2, dog, cat);
Pet pet1 = pet.clone();
System.out.println(pet);
System.out.println(pet1);
System.out.println(pet.getCat() == pet1.getCat());//true
System.out.println(pet.getDog() == pet1.getDog());//true
dog.setName("WangCai");
System.out.println(pet);
System.out.println(pet1);//浅克隆时,克隆体随之而改变
}
}
测试结果如下
三、深克隆的代码实现
第一种方法:重写clone方法,对每一个引用类型再进行clone
1.把上述Cat和Dog类都实现Cloneable接口
public class Cat implements Cloneable {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public Cat clone() throws CloneNotSupportedException {
Cat cloneCat = (Cat) super.clone();
return cloneCat;
}
}
public class Dog implements Cloneable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public Dog clone() throws CloneNotSupportedException {
Dog cloneDog = (Dog) super.clone();
return cloneDog;
}
}
2.重写Pet类里的clone方法,把Dog和Cat引用类型再分别进行clone
public class Pet implements Cloneable {//创建一个宠物类,实现Cloneable接口
private int quantity;
private Dog dog;//创建一个Dog引用类型
private Cat cat;//创建一个Cat引用类型
public Pet(int quantity, Dog dog, Cat cat) {
this.quantity = quantity;
this.dog = dog;
this.cat = cat;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Pet{" +
"quantity=" + quantity +
", dog=" + dog +
", cat=" + cat +
'}';
}
@Override
public Pet clone() throws CloneNotSupportedException {
//此处改为public Pet是方便后续创建的CloneTest类中的对象好调用clone()
Pet clonePet = (Pet) super.clone();
clonePet.dog = clonePet.dog.clone();
clonePet.cat = clonePet.cat.clone();
return clonePet;
}
}
3.测试深克隆效果
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog("Spike", 10);
Cat cat = new Cat("Tom", 12);
Pet pet = new Pet(2, dog, cat);
Pet pet1 = pet.clone();
System.out.println(pet);
System.out.println(pet1);
System.out.println(pet.getCat() == pet1.getCat());//false
System.out.println(pet.getDog() == pet1.getDog());//false
dog.setName("WangCai");
System.out.println(pet);
System.out.println(pet1);//深克隆时,克隆体不会随之而改变
}
}
测试结果如下
第二种方法:序列化和反序列化
1.准备好Cat、Dog、Pet三个类,三个类都实现Serializable接口
import java.io.Serializable;
public class Cat implements Serializable {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.io.Serializable;
public class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.io.Serializable;
public class Pet implements Serializable {
private int quantity;
private Dog dog;//创建一个Dog引用类型
private Cat cat;//创建一个Cat引用类型
public Pet(int quantity, Dog dog, Cat cat) {
this.quantity = quantity;
this.dog = dog;
this.cat = cat;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Pet{" +
"quantity=" + quantity +
", dog=" + dog +
", cat=" + cat +
'}';
}
}
2.创建一个SerializableCloneTest的类,进行序列化和反序列并且测试深克隆效果
import java.io.*;
public class SerializableCloneTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Dog dog = new Dog("Spike", 10);
Cat cat = new Cat("Tom", 12);
Pet pet = new Pet(2, dog, cat);
//创建一个字节数组输出流和一个二进制带类型的对象输出流,两个流搭配进行使用
ByteArrayOutputStream bAOut = new ByteArrayOutputStream();
ObjectOutputStream oOut = new ObjectOutputStream(bAOut);
oOut.writeObject(pet);//序列化要深克隆的对象
//创建一个字节数组输入流和一个二进制带类型的对象输入流,字节数组输入流读取bAOut
ByteArrayInputStream bAIn = new ByteArrayInputStream(bAOut.toByteArray());
ObjectInputStream oIn = new ObjectInputStream(bAIn);
//反序列化,把Object对象强转为Pet类型的对象,完成对Pet类型对象的深克隆
Pet clonePet = (Pet) oIn.readObject();
System.out.println(pet);
System.out.println(clonePet);
System.out.println(pet.getCat() == clonePet.getCat());//false
System.out.println(pet.getDog() == clonePet.getDog());//false
cat.setName("Hello Kitty");
System.out.println(pet);
System.out.println(clonePet);//深克隆时,克隆体不会随之而改变
bAOut.close();//使用完后关闭流
oOut.close();
bAIn.close();
oIn.close();
}
}
测试结果如下
四、结论
浅克隆就是简单把对象中引用类型的地址进行复制,被克隆对象的引用类型改变,会引发克隆对象也会发生改变(不包括不可变类)
想要克隆完整的独立的个体,只能采用深克隆,被克隆对象的改变不会引起克隆对象的改变,被克隆对象的引用类型过多的话,推荐使用序列化和反序列化进行深克隆,比较方便。
本文含有隐藏内容,请 开通VIP 后查看