java复制对象以及浅复制、深复制

本篇博客不讨论关于八种基本类型的复制,只讨论javaBean的复制,包括浅复制和深复制。

复制对象就是克隆对象,在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在 Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。若是采用先将A对象的属性取出来,然后在一个个set到B对象的属性中,不仅代码书写繁琐,维护也麻烦,更不用提到效率问题了。

废话不多说,直接奉上浅复制的代码示例:

public class ERPSaleData extends SaleDataExtend implements Cloneable{
  private String orderId;
 public String getOrderId() {
       return orderId;
  }

  public void setOrderId(String orderId) {
      this.orderId = orderId == null ? null : orderId.trim();
  }	

  @Override
  public ERPSaleData clone() {  
	ERPSaleData erpSaleData = null;  
        try{  
        	erpSaleData = (ERPSaleData)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return erpSaleData;  
    }
调用示例:

ERPSaleData data = new ERPSaleData();
ERPSaleData saleData = data.clone();

有三个值得注意的地方,

一是希望能实现clone功能的CloneClass类实现了Cloneable接口,这个接口属于java.lang 包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable。

另一个值得请注意的是重载了clone()方 法。最后在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什么样的,super.clone()直接或 间接调用了java.lang.Object类的clone()方法。下面再详细的解释一下这几点。 

应该说第三点是最重要的,仔细 观察一下Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为 什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。对于第二点,也要 观察Object类中的clone()还是一个protected属性的方法。这也意味着如果要应用clone()方法,必须继承Object类,在 Java中所有的类是缺省继承Object类的,也就不用关心这点了。然后重写clone()方法。还有一点要考虑的是为了让其它类能调用这个clone 类的clone()方法,重写之后要把clone()方法的属性设置为public。 

那么clone类为什么还要实现 Cloneable接口呢?稍微注意一下,Cloneable接口是不包含任何方法的!其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对 Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用了 super.Clone()方法),那么Object的clone()方法就会抛出CloneNotSupportedException异常。

以上讲的是浅复制,被复制的对象中并没有引用其他类对象。浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

这段是深复制的代码:

public class ERPSaleData extends SaleDataExtend implements Cloneable{
	
    private String orderId;
    
    private ERPSaleDetail detail;
    
    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId == null ? null : orderId.trim();
    }
    
    public ERPSaleDetail getDetail() {
		return detail;
	}
    
    public void setDetail(ERPSaleDetail detail) {
		this.detail = detail;
	}
    
    @Override
	public ERPSaleData clone() {  
		ERPSaleData erpSaleData = null;  
        try{  
        	erpSaleData = (ERPSaleData)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }
        erpSaleData.detail = (ERPSaleDetail)detail.clone();
        return erpSaleData;  
    }
} 
当然,引用对象也要实现Cloneable接口,调用方法是一样的,这里九部赘述了。

还有一种深拷贝方法,就是将对象串行化,这个还没有研究过,留着下一篇博客来解释吧。




猜你喜欢

转载自blog.csdn.net/cainiaobulan/article/details/79196262