★★ Java clone 详解(重点关注)

拷贝对象要细心

 

url: http://lsy.javaeye.com/blog/46189

 

在说对象的拷贝问题之前,先提一下java对参数的传递。在Java语言中通过值传递 机制将所有实参的值传递给方法,这就意味着方法将接受所有实参
的一个拷贝,看下面的代码:

Java代码 复制代码
  1. public  static  void  main(String[] args) {   
  2.     int  i = 1 ;   
  3.     int  j = 2 ;   
  4.     change(i,j);   
  5.     System.out.println(i+j);   
  6. }   
  7. public  static  void  change(int  i, int  j){   
  8.     i += 10 ;   
  9.     j += 10 ;   
  10. }  
	public static void main(String[] args) {
		int i = 1;
		int j = 2;
		change(i,j);
		System.out.println(i+j);
	}
	public static void change(int i, int j){
		i += 10;
		j += 10;
	}


打印结果是3,并不会影响到原来的变量值。但是如果方法接受的实参类型不是基本类型的变量,而是对象,那么Java语言运用的机制就是引用传递 。继续看代码:
先定义两个Dog类:

Java代码 复制代码
  1. public  class  Flea{   
  2.     private  String size;   
  3.     public  Flea(String size) {   
  4.         this .size = size;   
  5.     }   
  6. }   
  7. public  class  Dog {   
  8.     private  String name;    
  9.     private  int  age;       
  10.     private  Flea flea;   
  11.     public  Dog(String aName,int  age) {    
  12.         this .name = aName;    
  13.         this .age = age;    
  14.         this .flea = new  Flea("small" );         
  15.     }   
  16.     public  String toString(){   
  17.         return  "Dog age is " +age+"! Dog's flea size is " +flea.getSize();   
  18.     }   
  19. }  
public class Flea{
	private String size;
	public Flea(String size) {
		this.size = size;
	}
}
public class Dog {
	private String name; 
	private int age; 	
	private Flea flea;
	public Dog(String aName,int age) { 
		this.name = aName; 
		this.age = age; 
		this.flea = new Flea("small");		
	}
	public String toString(){
		return "Dog age is "+age+"! Dog's flea size is "+flea.getSize();
	}
}


接着

Java代码 复制代码
  1. public  static  void  main(String[] args) {   
  2.     Dog dog = new  Dog("Tom" ,10 );   
  3.     change(dog);   
  4.     System.out.println(dog);   
  5. }   
  6. public  static  void  change(Dog dog){   
  7.     dog.setAge(100 );   
  8.     dog.getFlea().setSize("big" );   
  9. }  
	public static void main(String[] args) {
		Dog dog = new Dog("Tom",10);
		change(dog);
		System.out.println(dog);
	}
	public static void change(Dog dog){
		dog.setAge(100);
		dog.getFlea().setSize("big");
	}


打印结果应该是Dog age is 100 ! Dog's flea size is big。这是因为传递给方法的变量是一个对象引用的副本,也就是说dog是一个对象的引用,而传递给方法的是dog这个引用的副本,因此二者引用的是同一个对象,因此在方法中对象改变了,那么方法外对象也会改变。这是要做的事情就是在对象传递给方法之前先做拷贝。因此修改一下Dog.java

Java代码 复制代码
  1. public  class  Flea implements  Cloneable {   
  2.     private  String size;   
  3.     public  Flea(String size) {   
  4.         this .size = size;   
  5.     }   
  6.     public  Object clone() {   
  7.         Flea newFlea = null ;   
  8.         try {   
  9.             newFlea = super .clone();   
  10.         }   
  11.         catch (CloneNotSupportedException e){}   
  12.         return  newFlea;   
  13.     }   
  14. }   
  15. public  class  Dog implements  Cloneable{   
  16.     private  String name;    
  17.     private  int  age;       
  18.     public  Dog(String aName, int  age) {    
  19.         this .name = aName;    
  20.         this .age = age;        
  21.         this .flea = new  Flea("small" );   
  22.     }   
  23.     public  Object clone() {   
  24.         Dog newDog = null ;   
  25.         try {   
  26.             newDog = super .clone();   
  27.         }   
  28.         catch (CloneNotSupportedException e){}   
  29.         return  newDog;   
  30.     }   
  31.     public  String toString(){   
  32.         return  "Dog age is " +age+"! Dog's flea size is " +flea.getSize();   
  33.     }   
  34. }  
public class Flea implements Cloneable {
	private String size;
	public Flea(String size) {
		this.size = size;
	}
	public Object clone() {
		Flea newFlea = null;
		try{
			newFlea = super.clone();
		}
		catch(CloneNotSupportedException e){}
		return newFlea;
	}
}
public class Dog implements Cloneable{
	private String name; 
	private int age; 	
	public Dog(String aName, int age) { 
		this.name = aName; 
		this.age = age; 	
		this.flea = new Flea("small");
	}
	public Object clone() {
		Dog newDog = null;
		try{
			newDog = super.clone();
		}
		catch(CloneNotSupportedException e){}
		return newDog;
	}
	public String toString(){
		return "Dog age is "+age+"! Dog's flea size is "+flea.getSize();
	}
}


接下来调整一下测试代码:

Java代码 复制代码
  1. public  static  void  main(String[] args) {   
  2.     Dog dog = new  Dog("Tom" ,10 );   
  3.     Dog cDog = (Dog)dog.clone();   
  4.     change(dog);   
  5.     System.out.println(dog);   
  6.     System.out.println(cDog);   
  7. }  
	public static void main(String[] args) {
		Dog dog = new Dog("Tom",10);
		Dog cDog = (Dog)dog.clone();
		change(dog);
		System.out.println(dog);
		System.out.println(cDog);
	}


可以看到打印结果是:
Dog age is 100! Dog's flea size is big
Dog age is 10! Dog's flea size is big
这时结果仍然不能让人满意,因为虽然Dog的age被保留了下来,但是Dog的Flea的size确仍然被改变了。这就是需要注意的地方,拷贝对象时留意对象的嵌套对象的拷贝,如此修改一下Dog的clone方法:

Java代码 复制代码
  1. public  Object clone() {   
  2.     Dog newDog = null ;   
  3.     try {   
  4.         newDog = (Dog)super .clone();   
  5.         newDog.flea = (Flea)flea.clone();//加上这一行   
  6.     }   
  7.     catch (CloneNotSupportedException e){}   
  8.     return  newDog;   
  9. }  
	public Object clone() {
		Dog newDog = null;
		try{
			newDog = (Dog)super.clone();
			newDog.flea = (Flea)flea.clone();//加上这一行
		}
		catch(CloneNotSupportedException e){}
		return newDog;
	}


再次运行一次,可以看到结果是:
Dog age is 100! Dog's flea size is big
Dog age is 10! Dog's flea size is small
这样就可以保留在调用方法之前的对象了。^_^

 

 

java中的clone机制

 

http://blog.csdn.net/hdy007/archive/2007/03/01/1518300.aspx

java中有两种clone方式,一种是浅拷贝,一种是深拷贝.
Object 定义了clone方法,而且定义为protected保护型,返回Object.

如果你要使自定义的类能够被clone,就必须实现Cloneable接口并且
重写clone()方法.



class CloneTest1() implements Cloneable
{
java.util.Date date;
public Object clone()
{
try {
   return super.clone();
}
catch (CloneNotSupportedException ex) {
    //如果没有实现Cloneable接口,抛出异常
return null;
}
  }
}

CloneTest1简单的实现了Clone()方法,只是简单的调用Object的clone()方法.
这种方式属于浅拷贝,只是clone了CloneTest1的表层.测试如下:
CloneTest1 src=new CloneTest1();
CloneTest1 des=(CloneTest1)src.clone();
System.out.println(src==des); //false 说明有两个CloneTest1的实例.
System.out.println(src.date==des.date); //true 指向相同的数据成员.

 

有时候我们需要一个完全的备份,就是深层次的拷贝

class CloneTest2 implements Cloneable{
java.util.Date date;
public Object clone(){
try {
   CloneTest2 ct=(CloneTest2)super.Clone();
   ct.date=date.clone();

   return ct;
}
catch (CloneNotSupportedException ex) {
return null;
}
}
}

上面的实现就是一个深拷贝了,要实现深拷贝类中的数据成员都得是Cloneable的(当然
你也可以不是,那就是自找麻烦):
class NotCloneable{
public String str;
}
class CloneTest3{
NotCloneable nc;
public clone(){
try
{
CloneTest3 ct=(CloneTest3)super.clone();
ct.nc=new NotCloneable();
ct.nc.str=str;
return ct;
}
catch (CloneNotSupportedException ex) {
return null;
}
}
}
这样虽然也实现了深拷贝,但是非常不好.

 

 

 

 

 

 

url: http://onlylove.javaeye.com/blog/265113

 

1,什么是Clone ?

简单地说, Clone 就是对于给定的一个对象实例 o ,得到另一个对象实例 o’oo’

型相同( o.getClass() == o’.getClass() ),内容相同(对于 o/o’ 中的字段 f ,如果 f 是基本数据类型,则 o.f == o’.f ;如果 f 是对象引用,则 o.f == o’.fo.f 指向的对象与 o’.f 指向的对象的内容相同)。通常称 o’o 的克隆或副本。

 

2,什么时候使用Clone?

      当需要修改对象属性,又不想影响原来的属性值,这时候就应该使用clone了。

 

3,  Javaclone 的支持

      万类之初的  Object  类有  clone()  方法:
       protected native Object clone() throws CloneNotSupportedException;
该方法是 protected 的,显然是留待被子类 override 的。该方法又是 native 的,必然做了
与具体平台相关的底层工作。
事实上,类 Object 的 clone() 方法首先会检查 this.getClass() 是否实现了 Cloneable 接口。
Cloneable 只是一个标志接口而已,用来标志该类是否有克隆功能。
public interface Cloneable {

}
     如果 this.getClass() 没有实现 Cloneable 接口, clone() 就会抛 CloneNotSupportedException 返回 。否则就会创建一个类型为 this.getClass() 的对象 other ,并将 this 各 field 的值赋值给 other 的对应 field ,然后返回 other 。
     如此一来,我们要定义一个具有 Clone 功能的类就相当方便:
     1.  在类的声明中加入“ implements Cloneable ”,标志该类有克隆功能;
     2. Override 类 Object 的 clone() 方法,在该方法中调用 super.clone() :

 

4,shallow clone  and deep clone

    Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅是简单地执行域对域的copy,这就是Shallow Clone。Java Collection 类库中具体数据结构类( ArrayList/LinkedListHashSet/TreeSetHashMap/TreeMap 等)都具有克隆功能,且都是 Shallow Clone。在有种情况下,这种shallow Clone就会问题,这个情况就是当,要clone的对象中的某个属性是一个引用, 这样克隆类就和原始类共享了一部分信息,对这个属性操作就会影响原始类,所以就需要deep clone.

 

举例见:http://onlylove.javaeye.com/blog/265113

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值