Java Clone研究

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

5、浅复制和深复制

     浅复制:简单地进行域对域的赋值,遇到引用类型,则表现为两个引用指向同一个对象

     深复制:针对引用类型成员在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为啥不行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值