Java实现深克隆
浅克隆实现与原理
java还提供了一个protected修饰的clone()方法,该方法用于帮助其他对象来实现”自我克隆”,所谓”自我克隆”就是得到一个当前对象的副本,而且二者之间完全隔离.由于Object类提供的clone()方法使用了protected修饰,因此该方法只能被子类重写或调用.
自定义类实现”克隆”的步骤如下:
1.自定义类实现Cloneable接口.这是一个标记性接口,实现该接口的对象可以实现”自我克隆”,接口里没有定义任何方法.
2. 自定义类实现自己的clone()方法;
3. 实现clone()方法时通过super.clone()调用Object实现的clone()方法来得到该对象的副本,并返回该副本;
下面用具体例子实现浅克隆:
public class CloneTest {
/**
* @param args
* @throws CloneNotSupportedException
*/
public static void main(String[] args) throws CloneNotSupportedException {
// TODO Auto-generated method stub
User u1 = new User(28);
// clone得到u1对象的副本
User u2 = u1.clone();
// 判断u1,u2是否相同
System.out.println(u1 == u2);// ①
// 判断u1,u2的address是否相同
System.out.println(u1.address == u2.address);// ②
u1.address. detail="hello";//③
System.out.println(u1.address.detail)//④
System.out.println(u2.address.detail)//⑤
}
}
class User implements Cloneable {
int age;
Address address;
/**
* @param age
* @param address
*/
public User(int age) {
super();
this.age = age;
this.address = new Address("商水县");
}
// 通过super.clone()来实现clone方法
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
class Address {
String detail;
/**
* @param detail
*/
public Address(String detail) {
super();
this.detail = detail;
}
}
上面程序让User类实现了Cloneable接口,而且实现了clone()方法,因此User对象就可实现”自我克隆”,克隆出来的对象只是原有对象的副本.程序在①处代码判断原有的User对象与克隆出来的User对象是否相同,程序返回false.
Object类提供的Clone机制只对对象里各实例变量进行”简单复制”,如果实例变量的类型是引用类型,Object的Clone机制也只是简单的复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例,所以上面程序中②处代码输出true 例如上面程序③号代码处改变了u1实例的address变量的detail变量的值 改为"hello"等到④,⑤代码处输出实例时全都从"商水县"改为"hello"
想要具体切断两个引用变量的关联就要实现浅克隆
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。
下面具体实现深克隆
package seven.three;
/**
* <br>
* 2019年12月1日下午3:57:56
*
* @author zjx
* @version 1.0
*/
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
User u1 = new User(28);
// u2得到u1对象的副本
User u2 = u1.clone();
// 判断u1,u2是否相同
System.out.println(u1 == u2);// ①
// 判断u,u2的address是否相同
System.out.println(u1.address == u2.address);// ②
// 改变对象u1的address引用的a数组索引的值
u1.address.a[1] = 1232;
// 输出对象u1的address引用的a数组索引1的值
System.out.println(u2.address.a[1]);③
// 改变对象u1的address引用的detail的值
u1.address.detail = "河南省";
// 输出u2对象的address引用的detail的值
System.out.println(u2.address.detail);④
}
}
class User implements Cloneable {
int age;
Address address;
public User(int age) {
super();
this.age = age;
this.address = new Address("商水县");
}
// 通过super.clone()来实现clone方法
public User clone() throws CloneNotSupportedException {
User user = (User) super.clone();
user.address = user.address.clone();
return user;
}
}
class Address implements Cloneable {
String detail;
int[] a = { 1, 2, 3, 5 };
public Address(String detail) {
super();
this.detail = detail;
}
public Address clone() throws CloneNotSupportedException {
Address address = (Address) super.clone();
address.a = address.a.clone();
return address;
}
}
上面程序让User类实现了Cloneable接口,而且实现了clone()方法,因此User对象就可实现”自我克隆”,克隆出来的对象只是原有对象的副本.程序在①处代码判断原有的User对象与克隆出来的User对象是否相同,程序返回false.
Object类提供的Clone机制只对对象里各实例变量进行跟深一步的深克隆,如果实例变量的类型是引用类型,则再对他的引用变量进行再次克隆②处代码输出false例 所以③号代码处输出的依旧是"商水县",④号代码处依旧是"2".