对于基本数据类型而言,即如下八种基本数据类型,int,boolean,char,byte,short,float,double,long。
1 public class test 2 { 3 public static void main(String[] args) 4 { 5 int a=3; 6 int b=a; 7 int c=3; 8 b=2; 9 System.out.println("a: "+a); 10 System.out.println("b: "+b); 11 System.out.println(a==b); 12 System.out.println(a==c); 13 14 } 15 }
说明:对于基本数据类型,==只是比较两个变量的值,并没有比较其地址,并且其变量复制后,任意改变其中一个变量时,并没有对另一个变量产生变化,默认实现的是深拷贝。
一个简单的浅拷贝示例,浅拷贝中复制出来的对象的域与原始对象的域使用相同的对象引用,指向的是同一个对象,相当于在两个对象中对同一个对象进行处理,会产生潜在的问题。
Object类的clone方法复制对象的做法是对当前对象中所有实例域进行逐一复制。先创建一个新的对象,再把新对象中所有的实例域的值初始化成原始对象中对应域的当前值。
1 class ToBeCloned implements Cloneable//Cloneable为标记接口,其内不包含任何方法,要实现此接口的话,必须重写clone方法,否则 2 //抛出异常java.lang.CloneNotSupportedException异常 3 { 4 private int value=0; 5 public void setValue(int value) 6 { 7 this.value=value; 8 } 9 public int getValue() 10 { 11 return this.value; 12 } 13 public Object clone() 14 { 15 try 16 { 17 return super.clone(); 18 } 19 catch(CloneNotSupportedException e) 20 { 21 throw new Error(e); 22 } 23 } 24 } 25 26 27 public class SimpleClone 28 { 29 public static void main(String[] args) 30 { 31 ToBeCloned obj=new ToBeCloned(); 32 obj.setValue(1); 33 ToBeCloned cloneObj=(ToBeCloned)obj.clone(); 34 35 System.out.println("cloneObj.getValue(): "+cloneObj.getValue()); 36 System.out.println("obj.getValue(): "+obj.getValue()); 37 obj.setValue(2); 38 System.out.println("cloneObj.getValue(): "+cloneObj.getValue()); 39 System.out.println("obj.getValue(): "+obj.getValue()); 40 } 41 }
如果对象中只包含值为基本类型或不可变对象的域,用上面的方法就可以了,内部域为基本数据类型。但是当对象中某些域的值为可变对象时,上述方法就不能满足了。示例如下:
1 class Counter 2 { 3 private int value=0; 4 public void increase() 5 { 6 value++; 7 } 8 public int getValue() 9 { 10 return value; 11 } 12 } 13 14 class MutableObject implements Cloneable 15 { 16 private Counter counter=new Counter(); 17 public void increase() 18 { 19 counter.increase(); 20 } 21 public int getValue() 22 { 23 return counter.getValue(); 24 } 25 public Object clone() 26 { 27 try 28 { 29 return super.clone(); 30 } 31 catch(CloneNotSupportedException e) 32 { 33 throw new Error(e); 34 } 35 } 36 } 37 38 39 public class MutableObjectClone 40 { 41 public static void main(String[] args) 42 { 43 MutableObject obj=new MutableObject(); 44 obj.increase(); 45 MutableObject clonedObj=(MutableObject)obj.clone(); 46 clonedObj.increase(); 47 obj.increase(); 48 System.out.println(clonedObj.getValue()); 49 System.out.println(obj.getValue()); 50 } 51 }
这说明Object类的clone方法已经对类中的基本类型和不可变对象的域进行了处理,只要在这基础上添加对可变对象的域的处理即可。即通过递归的方式来对clone进行修改。
因为在Counter中value为int类型,故递归截止为此函数。
1 class Counter implements Cloneable 2 { 3 private int value=0; 4 public void increase() 5 { 6 value++; 7 } 8 public int getValue() 9 { 10 return value; 11 } 12 public Object clone() 13 { 14 try 15 { 16 return super.clone(); 17 } 18 catch(CloneNotSupportedException e) 19 { 20 throw new Error(e); 21 } 22 } 23 } 24 25 class MutableObject implements Cloneable 26 { 27 private Counter counter=new Counter(); 28 public void increase() 29 { 30 counter.increase(); 31 } 32 public int getValue() 33 { 34 return counter.getValue(); 35 } 36 public Object clone() 37 { 38 MutableObject obj; 39 try 40 { 41 obj=(MutableObject)super.clone(); 42 obj.counter=(Counter)counter.clone(); 43 return obj; 44 } 45 catch(CloneNotSupportedException e) 46 { 47 throw new Error(e); 48 } 49 } 50 } 51 52 53 public class MutableObjectClone 54 { 55 public static void main(String[] args) 56 { 57 MutableObject obj=new MutableObject(); 58 obj.increase(); 59 MutableObject clonedObj=(MutableObject)obj.clone(); 60 clonedObj.increase(); 61 obj.increase(); 62 obj.increase(); 63 System.out.println("clonedObj.getValue(): "+clonedObj.getValue()); 64 System.out.println("obj.getValue(): "+obj.getValue()); 65 } 66 }
在这里要注意在类Object中,clone()方法是protected权限的。
进行复制对象的另外一个做法是使用复制构造方法,即用一个已有 的对象去构造另外一个对象。
示例如下:
1 public class UserException 2 { 3 private String name; 4 private String email; 5 6 public User(String name,String email) 7 { 8 this.name=name; 9 this.email=email; 10 } 11 public User(User user) 12 { 13 this.name=user.getName(); 14 this.email=user.getEmail(); 15 } 16 17 public String getName() 18 { 19 return this.name; 20 } 21 public String getEmail() 22 { 23 return this.email; 24 } 25 }