Java Clone
平時(shí)項(xiàng)目中用的也不多庄岖,今天來實(shí)踐下Java的Clone脖含。Clone主要分為“淺拷貝”與“深拷貝”。
“淺拷貝”: 實(shí)現(xiàn)Cloneable
接口投蝉,簡單的調(diào)用super.clone();
即能實(shí)現(xiàn)养葵,如:
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
“深拷貝”: 雖然實(shí)現(xiàn)Cloneable
接口也能去實(shí)現(xiàn)“深拷貝”,但會非常繁瑣瘩缆,而且引用層級很多的情況下关拒,需要給每個(gè)類的clone方法都去添加相應(yīng)的clone邏輯,所以一般不用庸娱。最簡單的就是用序列化方式
去完成“深拷貝”,如:
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) {
T cloneObj = null;
try {
// 寫入字節(jié)流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
// 分配內(nèi)存着绊,寫入原始對象,生成新對象
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>
舉個(gè)栗子
Car
,有車標(biāo)CarMark
熟尉,輪子的集合Tire
set
實(shí)現(xiàn)Cloneable
是為了“淺拷貝”归露, 實(shí)現(xiàn)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]
從結(jié)果看出,通過調(diào)用car.clone();
方式斤儿,不管是Car
的引用(CarMark
)剧包,還是Car
引用的引用(具體某個(gè)Tire
)恐锦,都指向同一個(gè)對象,這就是“淺拷貝”
而通過調(diào)用CloneUtils.clone(car);
都是指向不同的對象疆液,這就是“深拷貝”
</br>
</br>
Code:
</br>
</br>