java 浅克隆_Java浅克隆和深克隆深入理解

一、何为克隆

在Java的体系中,数据类型分为基本数据类型和引用数据类型。

基本数据类型包括byte,short,int,long,float,double,boolean,char 8种,其克隆可通过赋值运算实现,比如

int a = 1;

int b = a;

引用类型的克隆的实现方式有以下两种:

1)实现Cloneable接口,重写clone() 方法,修改clone() 方法的修饰符为public。其分为浅克隆和深克隆。

2)  实现Serializable接口,对实例进行序列化,通过二进制流反序列化。其为真正的克隆。

注:若类没实现Cloneable接口,调用对象的clone方法会抛出CloneNotSupportedException异常

二、重写clone实现克隆

克隆就是获得当前对象的副本,其与当前对象是内存地址不同的两个对象。

浅克隆指的是当前对象的实例成员为引用类型时,副本的该实例成员只是复制了其引用值,指向同一个对象。

深克隆则是对该引用指向的对象进行克隆,然后引用指向了该副本,指向不同的对象。

浅克隆导致了一个问题就是,对实例或克隆副本做出的改变会影响彼此,从而导致错误的结果,下面的例子可以说明:

汽车类 Car,包含一个引用类型成员brand:

/**

* Car类

* 实现Cloneable接口,重写clone方法

* @author zhangyj

*

*/

public class Car implements Cloneable{

//使用年限

private int year;

//品牌

private Brand brand;

public int getYear() {

return year;

}

public void setYear(int year) {

this.year = year;

}

public Brand getBrand() {

return brand;

}

public void setBrand(Brand brand) {

this.brand = brand;

}

//构造器

public Car(int year, Brand brand) {

this.year = year;

this.brand = brand;

}

/**

* 浅克隆,调用父类的clone方法

*/

@Override

public Object clone() {

Object obj = null;

try {

obj = super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return obj;

}

/**

* 深克隆,其引用类型成员也要调用clone

* @return

*/

public Car deepClone() {

Car car = null;

try {

car = (Car)super.clone();

car.setBrand((Brand)brand.clone());

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return car;

}

@Override

public String toString() {

return "[year=" + year + ", brand=" + brand + "]";

}

}

/**

* 品牌类

* @author zhangyj

*

*/

class Brand implements Cloneable{

//名称

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

@Override

protected Object clone() {

Object obj = null;

try {

obj = super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return obj;

}

public Brand(String name) {

this.name = name;

}

@Override

public String toString() {

return "Brand [name=" + name + "]";

}

}

测试类 CarCloneTest :

public class CarCloneTest {

public static void main(String[] args) {

Brand brand = new Brand("BMW");

Car car = new Car(5, brand);

Car carClone;

carClone = (Car) car.clone();  //(1)

//carClone = (Car) car.deepClone(); //(2)

System.out.println("******************************************");

System.out.println("car "+car);

System.out.println("carClone "+carClone);

System.out.println("******************************************");

System.out.println("将car年限改为 7,品牌名称改为Banz");

brand.setName("Banz");

car.setYear(7);

System.out.println("******************************************");

System.out.println("car "+car);

System.out.println("carClone "+carClone);

}

}

浅克隆测试,运行(1)代码,得到结果如下:

******************************************

car [year=5, brand=Brand [name=BMW]]

carClone [year=5, brand=Brand [name=BMW]]

******************************************

将car年限改为 7,品牌名称改为Banz

******************************************

car [year=7, brand=Brand [name=Banz]]

carClone [year=5, brand=Brand [name=Banz]]

可见当修改car中brand对象的名称为Banz时,carClone也跟着改变,可见其引用的brand对象为同一个,显然这不是我们想要的,而深克隆就解决了这个问题。

深克隆测试,运行(2)代码,得到结果如下:

******************************************

car [year=5, brand=Brand [name=BMW]]

carClone [year=5, brand=Brand [name=BMW]]

******************************************

将car年限改为 7,品牌名称改为Banz

******************************************

car [year=7, brand=Brand [name=Banz]]

carClone [year=5, brand=Brand [name=BMW]]

三、序列化实现深克隆

序列化对象必须实现Serializable接口,使对象可序列化。

public class Car implements Serializable{

private static final long serialVersionUID = 7883197573658810857L;

private int year; //使用年限

private Brand brand; //品牌

public int getYear() {

return year;

}

public void setYear(int year) {

this.year = year;

}

public Brand getBrand() {

return brand;

}

public void setBrand(Brand brand) {

this.brand = brand;

}

public Car(int year, Brand brand) {

this.year = year;

this.brand = brand;

}

@Override

public String toString() {

return "[year=" + year + ", brand=" + brand + "]";

}

}

class Brand implements Serializable{

private static final long serialVersionUID = -6505899377489945908L;

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Brand(String name) {

this.name = name;

}

@Override

public String toString() {

return "Brand [name=" + name + "]";

}

}

克隆工具类 CloneUtil:

public final class CloneUtil {

private CloneUtil() { throw new AssertionError(); }

/**

* 序列化实现深克隆

* @param t 泛型对象

* @return

*/

@SuppressWarnings("unchecked")

public static T deepClone(T t) {

ByteArrayOutputStream out = new ByteArrayOutputStream();

ObjectOutputStream objOut;

ObjectInputStream objIn;

T tClone = null ;

try {

objOut = new ObjectOutputStream(out);

objOut.writeObject(t);  //将对象以二进制流形式写入

ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

objIn = new ObjectInputStream(in);

tClone = (T)objIn.readObject(); //反序列化读取对象

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return tClone;

}

}

测试类 CarCloneTest:

public class CarCloneTest {

public static void main(String[] args) {

Brand brand = new Brand("BMW");

Car car = new Car(5, brand);

Car carClone;

//        carClone = (Car) car.clone();  //(1)

//        carClone = (Car) car.deepClone(); //(2)

carClone = CloneUtil.deepClone(car);

System.out.println("******************************************");

System.out.println("car "+car);

System.out.println("carClone "+carClone);

System.out.println("******************************************");

System.out.println("将car年限改为 7,品牌名称改为Banz");

brand.setName("Banz");

car.setYear(7);

System.out.println("******************************************");

System.out.println("car "+car);

System.out.println("carClone "+carClone);

}

}

运行测试程序,得到结果如下:

******************************************

car [year=5, brand=Brand [name=BMW]]

carClone [year=5, brand=Brand [name=BMW]]

******************************************

将car年限改为 7,品牌名称改为Banz

******************************************

car [year=7, brand=Brand [name=Banz]] carClone [year=5, brand=Brand [name=BMW]]

可见通过反序列化对象进行克隆也能得到我们想要的结果。

以上!

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值