1、Clone出处
Object中方法:protected nativeObject clone() throws CloneNotSupportedException;
2、自定义对象如何重定义clone
(1)实现Cloneable接口(必须,否则调用clone方法报异常CloneNotSupportedException)
(2)重写Object类的clone()方法,内部调用Object类的clone方法实现(super.clone())
3、clone结果
==操作符返回false
equals在默认情况下采用了==实现,因此默认是false
getClass返回值相等
4、哪些类实现了cloneable接口
实现了cloneable接口:Object、Date、数组
没有实现cloneable接口:String、StringBuffer
浅复制:简单地进行域对域的赋值,遇到引用类型,则表现为两个引用指向同一个对象
深复制:针对引用类型成员在clone时创建一个新的对象
6、代码测试
public class Dog implements Cloneable{
private int type;
private String name; // 引用类型,没有实现cloneable接口,默认结果为浅克隆,【但实际使用过程中却表现为深克隆,因为String在内存中不可变,对其值改动时实际上是新建了一个对象】
private StringBuffer sb; // 引用类型,没有实现cloneable接口,默认结果为浅克隆
private Date birth; // 引用类型,实现了cloneable接口,自动表现为深克隆?
private Address addr; // 引用类型,自定义对象,默认没有实现cloneable接口,默认结果为浅克隆,如需深克隆,则手动处理
private int[] goodDays; // 引用类型,默认结果为浅克隆
public Dog(){
}
public Dog(int type,String name,Date birth,Address addr,int[] srcArr,StringBuffer srcSb){
this.type = type;
this.name = name;
this.birth = birth;
this.addr = addr;
this.goodDays = srcArr;
this.sb = srcSb;
}
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object clone() throws CloneNotSupportedException{
Dog dog = null;
try {
dog = (Dog)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
dog.sb = new StringBuffer(this.sb);
dog.birth = (Date)this.birth.clone();
dog.addr = (Address)this.addr.clone();
dog.goodDays = this.goodDays.clone();
return dog;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public int[] getGoodDays() {
return goodDays;
}
public void setGoodDays(int[] goodDays) {
this.goodDays = goodDays;
}
public StringBuffer getSb() {
return sb;
}
public void setSb(StringBuffer sb) {
this.sb = sb;
}
}
public class Address implements Cloneable{
private String addr;
public Address(String addr){
this.addr = addr;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException, ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
Address addr = new Address("inside");
int[] srcArr = new int[]{1,2,3};
StringBuffer srcSb = new StringBuffer("hehe");
Dog dog1 = new Dog(1,"tommy",calendar.getTime(),addr,srcArr,srcSb);
Dog dog2 = (Dog)dog1.clone();
System.out.println(dog1.equals(dog2)); // false,自定义类没有重写Object.equals()方法,默认采用父类实现,即比较引用是否相等
System.out.println(dog1 == dog2); // false
System.out.println(dog1.getClass() == dog2.getClass()); // false
System.out.println(dog1.getClass().equals(dog2.getClass())); // false
System.out.println(dog2.getName());
System.out.println(dog2.getType());
System.out.println(sdf.format(dog2.getBirth()));
System.out.println(dog2.getAddr().getAddr());
System.out.println(Arrays.toString(dog2.getGoodDays()));
System.out.println(dog2.getSb().toString());
dog2.setName("jimmy");
dog2.setType(2); // 修改时间
calendar.add(Calendar.DAY_OF_MONTH, 2);
dog2.setBirth(calendar.getTime()); // 修改住址
dog2.getAddr().setAddr("outside"); // 修改引用成员变量
dog2.getGoodDays()[1] = 2222; // 修改数组成员变量
dog2.getSb().append(" java");
System.out.println(dog2.getName());
System.out.println(dog2.getType());
System.out.println(sdf.format(dog2.getBirth()));
System.out.println(dog2.getAddr().getAddr());
System.out.println(Arrays.toString(dog2.getGoodDays()));
System.out.println(dog2.getSb().toString());
System.out.println(dog1.getName());
System.out.println(dog1.getType());
System.out.println(sdf.format(dog1.getBirth()));
System.out.println(dog1.getAddr().getAddr());
System.out.println(Arrays.toString(dog1.getGoodDays()));
System.out.println(dog1.getSb().toString());
// dog1和dog2的birthDate还是一个对象吗
System.out.println(dog2.getBirth() == dog1.getBirth()); // false,说明Date自动克隆了,因为它已经实现了cloneable接口
// dog1和dog2的goodDays还是一个对象吗
System.out.println(dog2.getGoodDays() == dog1.getGoodDays()); // true,说明是浅克隆
int[] iArr = new int[]{1,2,3};
int[] clonedArr = iArr.clone(); // 数组实现了cloneable接口
clonedArr[1] = 2002;
System.out.println(Arrays.toString(clonedArr)); // 打印实际数组元素
System.out.println(Arrays.toString(iArr)); // 打印实际数组元素, not changed
System.out.println(clonedArr == iArr); // false
7、结论
引用类型成员除了String之外,均需要处理深浅复制问题
测试发现Date会自动进行深复制,为什么呢,如果它是实现了cloneable接口导致的,那数组也实现了cloneable为啥不行