在程序开发过程中,有时候我们需要一个对象的副本,我们对该副本的操作不能影响到原对象中的数据,这时候,我们就需要对该对象进行一个复制版本,也就是我要说的克隆Clone.
Clone方法原型介绍
在讲对象的克隆之前,我们先来了解一下Clone方法存在哪里,Clone方法是Object类中声明的一个protected访问权限的本地方法.
clone方法原型如下:
protected native Object clone() throws CloneNotSupportedException;
Cloneable接口介绍
如果我们想让我们自己定义的类支持Clone,那么我们的类就必须实现Cloneable 接口.
通过接口的定义我们知道这是一个没有声明任何方法的空接口.
package java.lang;
public interface Cloneable {
}
类实现了Cloneable接口的作用:
类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
原始类型(int,double,String…)的字段复制会得到新的值地址,但是引用类型(如自己定义的JavaBean)系统默认是使用原对象的引用,也就是说clone后对象的引用型成员依旧是指向原来的地址. 这也就是常说的系统默认的克隆是浅层次的克隆.
注意:
- 如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出
CloneNotSupportedException 异常。 - 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
浅层次克隆(系统默认的克隆)
好了上面做了那么多的前提准备,现在开始一个系统默认的克隆,我们来看看效果.
总结-浅层次clone步骤:
- 1.要被clone的类必须要实现接口Cloneable;
- 2.在要被Clone的类中覆写Object中的clone方法(有异常抛出),.将访问权限由protected改为public权限,以便可以操作该方法.为了方便可以將返回值类型Object类型具体化为本类对象.
package cn.com.yves.object.clone.newclone.noclone;
/**
*
*
* @author Yves He
*
*/
public class Cart implements Cloneable {
private String id;
private String creater;
private Shop shop;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreater() {
return creater;
}
public void setCreater(String creater) {
this.creater = creater;
}
public Shop getShop() {
return shop;
}
public void setShop(Shop shop) {
this.shop = shop;
}
@Override
public Cart clone() throws CloneNotSupportedException {
return (Cart) super.clone();
}
}
package cn.com.yves.object.clone.newclone.noclone;
/**
*
*
* @author Yves He
*
*/
public class Generic {
private String color;
private double size;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
}
package cn.com.yves.object.clone.newclone.noclone;
/**
*
*
* @author Yves He
*
*/
public class Shop {
private String name;
private double price;
private Generic gen; // 一般的参数
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Generic getGen() {
return gen;
}
public void setGen(Generic gen) {
this.gen = gen;
}
}
测试方法:
/**
* 原始类型(int,double,String...)的字段复制会得到新的值地址,但是引用类型(如自己定义的JavaBean)
* 系统默认是使用原对象的引用,也就是说clone后对象的引用型成员依旧是指向原来的地址. 这也就是常说的系统默认的克隆是浅层次的克隆.
*
* @param args
*/
public static void main(String[] args) {
Generic gen = new Generic();
gen.setColor("red");
gen.setSize(100);
Shop shop = new Shop();
shop.setName("BMW");
shop.setPrice(100000);
shop.setGen(gen);
Cart cart = new Cart();
cart.setCreater("Yves");
cart.setId(UUID.randomUUID().toString());
cart.setShop(shop);
try {
Cart cartClone = cart.clone();
System.out.println(cartClone == cart);// false
System.out.println(cartClone.getShop() == cart.getShop());// true,
// 可见系统默认的克隆是没有对引用型进行克隆,而是保留了原来的引用,也不是为null
System.out.println(cartClone.getShop().getGen() == cart.getShop().getGen());// true,原理同上
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
PS : 下篇文章介绍深层次克隆~