Java Clone
平时项目中用的也不多,今天来实践下Java的Clone。Clone主要分为“浅拷贝”与“深拷贝”。
“浅拷贝”: 实现Cloneable
接口,简单的调用super.clone();
即能实现,如:
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
“深拷贝”: 虽然实现Cloneable
接口也能去实现“深拷贝”,但会非常繁琐,而且引用层级很多的情况下,需要给每个类的clone方法都去添加相应的clone逻辑,所以一般不用。最简单的就是用序列化方式
去完成“深拷贝”,如:
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) {
T 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 = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
</br>
</br>
举个栗子
Car
,有车标CarMark
,轮子的集合Tire
set
实现Cloneable
是为了“浅拷贝”, 实现Serializable
是为了“深拷贝”
public class Car implements Cloneable, Serializable{
private static final long serialVersionUID = 855536990529969854L;
private CarMark carMark;
private LinkedHashSet<Tire> tireSet;
public Car(CarMark carMark, LinkedHashSet<Tire> tireSet) {
super();
this.carMark = carMark;
this.tireSet = tireSet;
}
public CarMark getCarMark() {
return carMark;
}
public void setCarMark(CarMark carMark) {
this.carMark = carMark;
}
public LinkedHashSet<Tire> getTireSet() {
return tireSet;
}
public void setTireSet(LinkedHashSet<Tire> tireSet) {
this.tireSet = tireSet;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CarMark implements Serializable {
private static final long serialVersionUID = -840209218449463080L;
private String name;
private int historyInYears;
public CarMark(String name, int historyInYears) {
super();
this.name = name;
this.historyInYears = historyInYears;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHistoryInYears() {
return historyInYears;
}
public void setHistoryInYears(int historyInYears) {
this.historyInYears = historyInYears;
}
}
public class Tire implements Serializable{
private static final long serialVersionUID = -4185789610721446662L;
private TirePosition tirePosition;
private int wear;
public Tire(TirePosition tirePosition, int wear) {
super();
this.tirePosition = tirePosition;
this.wear = wear;
}
public TirePosition getTirePosition() {
return tirePosition;
}
public void setTirePosition(TirePosition tirePosition) {
this.tirePosition = tirePosition;
}
public int getWear() {
return wear;
}
public void setWear(int wear) {
this.wear = wear;
}
}
public enum TirePosition{
LEFT_FRONT, RIGHT_FRONT, LEFT_REAR, RIGHT_REAR
}
Builder 造车
public class CarBuilder {
public static Car buidFerrari(){
CarMark carMark = new CarMark("Ferrari", 70);
LinkedHashSet<Tire> tireSet = new LinkedHashSet<Tire>();
tireSet.add(new Tire(TirePosition.LEFT_FRONT, 0));
tireSet.add(new Tire(TirePosition.RIGHT_FRONT, 0));
tireSet.add(new Tire(TirePosition.LEFT_REAR, 0));
tireSet.add(new Tire(TirePosition.RIGHT_REAR, 0));
Car car = new Car(carMark, tireSet);
return car;
}
}
Main方法比较“浅拷贝”与“深拷贝”
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Car car = CarBuilder.buidFerrari();
Car clonedCar = (Car) car.clone();
String result = "使用Cloneable接口: " + (car.getCarMark() == clonedCar.getCarMark() ? "clone是浅拷贝的" : "clone是深拷贝的");
System.out.println(result);
System.out.println(car.getCarMark().toString());
System.out.println(clonedCar.getCarMark().toString());
System.out.println(car.getTireSet().toString());
System.out.println(clonedCar.getTireSet().toString());
System.out.println("-------------------------------------------");
Car deepClonedCar = CloneUtils.clone(car);
result = "使用序列化方式: " + (car.getCarMark() == deepClonedCar.getCarMark() ? "clone是浅拷贝的" : "clone是深拷贝的");
System.out.println(result);
System.out.println(car.getCarMark().toString());
System.out.println(deepClonedCar.getCarMark().toString());
System.out.println(car.getTireSet().toString());
System.out.println(deepClonedCar.getTireSet().toString());
}
}
输出
使用Cloneable接口: clone是浅拷贝的
sample.hibernate4.car.CarMark@70dea4e
sample.hibernate4.car.CarMark@70dea4e
[sample.hibernate4.car.Tire@15db9742, sample.hibernate4.car.Tire@6d06d69c, sample.hibernate4.car.Tire@7852e922, sample.hibernate4.car.Tire@4e25154f]
[sample.hibernate4.car.Tire@15db9742, sample.hibernate4.car.Tire@6d06d69c, sample.hibernate4.car.Tire@7852e922, sample.hibernate4.car.Tire@4e25154f]
-------------------------------------------
使用序列化方式: clone是深拷贝的
sample.hibernate4.car.CarMark@70dea4e
sample.hibernate4.car.CarMark@2f4d3709
[sample.hibernate4.car.Tire@15db9742, sample.hibernate4.car.Tire@6d06d69c, sample.hibernate4.car.Tire@7852e922, sample.hibernate4.car.Tire@4e25154f]
[sample.hibernate4.car.Tire@6f496d9f, sample.hibernate4.car.Tire@723279cf, sample.hibernate4.car.Tire@10f87f48, sample.hibernate4.car.Tire@b4c966a]
从结果看出,通过调用car.clone();
方式,不管是Car
的引用(CarMark
),还是Car
引用的引用(具体某个Tire
),都指向同一个对象,这就是“浅拷贝”
而通过调用CloneUtils.clone(car);
都是指向不同的对象,这就是“深拷贝”
</br>
</br>
Code:
</br>
</br>
网友评论