Object类的clone方法如下定义
protected Object clone() // 创建并返回此对象的一个副本
这意味着:这只能在内部调用,外部不能像这样new XXOBJECT().clone()直接调用。
clone方法是本地方法,是native的,要想实现克隆功能,子类需要做到如下几步:
1 声明实现Cloneable接口(Object没有实现,所以会抛出异常,同时也说明子类需要克隆则也需要重写clone方法)。
2 调用super.clone得到一个对象(注意:对于基本数据类型和不可变类型(String)的克隆是相等且独立的,即操作互不影响)
3 把浅copy的引用指向原型对象新的克隆体
(引用类型如果不进行深拷贝,则clone出来的对象都指向同一个。
ArrayList克隆方法:
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
//引用类型重新底层copy,使互不干扰
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
)。
看下例子:
public class Test {
static class User implements Cloneable {
String name;
int age;
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
static class Account implements Cloneable {
User user;
long balance;
@Override
public Account clone() throws CloneNotSupportedException {
Account account = (Account) super.clone();
if (user != null) {//user引用类型,如果不克隆的话,则user会互相影响操作,即操作的是同一对象
account.user = user.clone();
}
return account;
}
}
public static void main(String[] args) {
try {
User user = new User();
user.name = "cfx";
Account a1 = new Account();
a1.balance = 1000;
a1.user = user;
Account a2 = a1.clone();
System.out.println("clone对于基本数据类型和不可变类型(String)是相等且独立的");
System.out.println(a1.balance);
a1.balance = 20000;
System.out.println(a2.balance);
System.out.println("clone对于应用类型,克隆之后指向的是同一个对象,相互操作影响");
System.out.println(a2.user.name);
System.out.println(a2.user.name);
a1.user.name = "cfx2";
System.out.println(a2.user.name);
System.out.println(a2.user);//虽然指向的都是同一个内存地址,但user所有属性变量却不相同,这点确实有点怪
System.out.println(a2.user);
} catch (Exception e) {
e.printStackTrace();
}
}
问题来了,为什么要克隆?
试想一下,如果不clone(),那么如果你想副本对象跟原本对象具有相同值的属性,那么
你是不是需要写很多的代码来维护field...
再说,clone效率是很快滴...
protected Object clone() // 创建并返回此对象的一个副本
这意味着:这只能在内部调用,外部不能像这样new XXOBJECT().clone()直接调用。
clone方法是本地方法,是native的,要想实现克隆功能,子类需要做到如下几步:
1 声明实现Cloneable接口(Object没有实现,所以会抛出异常,同时也说明子类需要克隆则也需要重写clone方法)。
2 调用super.clone得到一个对象(注意:对于基本数据类型和不可变类型(String)的克隆是相等且独立的,即操作互不影响)
3 把浅copy的引用指向原型对象新的克隆体
(引用类型如果不进行深拷贝,则clone出来的对象都指向同一个。
ArrayList克隆方法:
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
//引用类型重新底层copy,使互不干扰
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
)。
看下例子:
public class Test {
static class User implements Cloneable {
String name;
int age;
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
static class Account implements Cloneable {
User user;
long balance;
@Override
public Account clone() throws CloneNotSupportedException {
Account account = (Account) super.clone();
if (user != null) {//user引用类型,如果不克隆的话,则user会互相影响操作,即操作的是同一对象
account.user = user.clone();
}
return account;
}
}
public static void main(String[] args) {
try {
User user = new User();
user.name = "cfx";
Account a1 = new Account();
a1.balance = 1000;
a1.user = user;
Account a2 = a1.clone();
System.out.println("clone对于基本数据类型和不可变类型(String)是相等且独立的");
System.out.println(a1.balance);
a1.balance = 20000;
System.out.println(a2.balance);
System.out.println("clone对于应用类型,克隆之后指向的是同一个对象,相互操作影响");
System.out.println(a2.user.name);
System.out.println(a2.user.name);
a1.user.name = "cfx2";
System.out.println(a2.user.name);
System.out.println(a2.user);//虽然指向的都是同一个内存地址,但user所有属性变量却不相同,这点确实有点怪
System.out.println(a2.user);
} catch (Exception e) {
e.printStackTrace();
}
}
问题来了,为什么要克隆?
试想一下,如果不clone(),那么如果你想副本对象跟原本对象具有相同值的属性,那么
你是不是需要写很多的代码来维护field...
再说,clone效率是很快滴...