锁定老帖子 主题:java clone方法使用详解
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-04-15
最后修改:2010-12-31
http://tuzki.us 我们都是兔斯基
----------------------------------------我是小小分割线--------------------------------
Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,特别是先学c、c++后学java的程序员。并且由于Java不能通过简单的赋值来解决对象复制的问题,在开发过程中,也常常要要应用clone()方法来复制对象。比如函数参数类型是自定义的类时,此时便是引用传递而不是值传递。以下是一个小例子: public class A { public String name; }
public class testClone { public void changeA(A a){ a.name="b"; } public void changInt(int i){ i=i*2+100; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub testClone test=new testClone(); A a=new A(); a.name="a"; System.out.println("before change : a.name="+a.name); test.changeA(a); System.out.println("after change : a.name="+a.name); int i=1; System.out.println("before change : i="+i); test.changInt(i); System.out.println("after change : i="+i); } }
before change : a.name=a after change : a.name=b before change : i=1 after change : i=1
A a1=new A(); A a2=new A(); a1.name="a1"; a2=a1; a2.name="a2"; System.out.println("a1.name="+a1.name); System.out.println("a2.name="+a2.name);
a1.name=a2 a2.name=a2
public class A implements Cloneable { public String name; public Object clone() { A o = null; try { o = (A) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } }
A a1=new A(); A a2=new A(); a1.name="a1"; a2=a1; a2.name="a2"; System.out.println("a1.name="+a1.name); System.out.println("a2.name="+a2.name);
a1.name=a1 a2.name=a2
public class A implements Cloneable { public String name[]; public A(){ name=new String[2]; } public Object clone() { A o = null; try { o = (A) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } }
A a1=new A(); A a2=new A(); a1.name[0]="a"; a1.name[1]="1"; a2=(A)a1.clone(); a2.name[0]="b"; a2.name[1]="1"; System.out.println("a1.name="+a1.name); System.out.println("a1.name="+a1.name[0]+a1.name[1]); System.out.println("a2.name="+a2.name); System.out.println("a2.name="+a2.name[0]+a2.name[1]);
a1.name=[Ljava.lang.String;@757aef a1.name=b1 a2.name=[Ljava.lang.String;@757aef a2.name=b1
public Object clone() { A o = null; try { o = (A) super.clone(); o.name=(String[])name.clone();//其实也很简单^_^ } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; }
a1.name=[Ljava.lang.String;@757aef a1.name=a1 a2.name=[Ljava.lang.String;@d9f9c3 a2.name=b1
public class A implements Cloneable { public String name[]; public Vector<B> claB; public A(){ name=new String[2]; claB=new Vector<B>(); } public Object clone() { A o = null; try { o = (A) super.clone(); o.name==(String[])name.clone();//深度clone o.claB=new Vector<B>();//将clone进行到底 for(int i=0;i<claB.size();i++){ B temp=(B)claB.get(i).clone();//当然Class B也要实现相应clone方法 o.claB.add(temp); } } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-09-08
A a1=new A();
A a2=new A(); a1.name="a1"; a2=a1; a2.name="a2"; System.out.println("a1.name="+a1.name); System.out.println("a2.name="+a2.name); result: a1.name=a2 a2.name=a2 Obviously, It is not correct. Pls confirm whether you copy error coding.The sentence "a2=(A)a1.clone();" should be used, instead "a2=a1;" |
|
返回顶楼 | |
发表时间:2008-09-08
Your deep clone coding is also not correct.
The correct coding should be: public class A implements Cloneable { public String name; public String[] group = new String[2]; public Object clone() { A o = null; try { o = (A) super.clone(); o.group = (String[])group.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } } |
|
返回顶楼 | |
发表时间:2008-09-09
Why Clone
Suppose you have an object ‘a’ of class ‘A’. Sometimes you may need another new object ‘b’. It also belongs to class ‘A’ and has the same data with object ‘a’. But if you do some modification on b, it has no effect to the value of ‘a’. We call this process which produced new object ‘b’ as clone object ‘a’. The commonest time that you need to clone an object is when it is a parameter or return value of one of your public methods. If it is a parameter that you save somewhere, then you don't want the caller to be able to modify it later. So you save a copy of the object. Likewise, if you are returning an object that is part of your class's internal state, you need to return a copy instead so that callers can't accidentally or deliberately change that internal state. Conventions of clone 1. x.clone() != x // x.clone() will return a new object 2. x.clone().equals(x) // this is the meaning of ‘copy’ 3. x.clone().getClass() == x.getClass() 4. The object returned by clone method should be independent of the object (which is being cloned). These are not absolute requirements but are general intends of clone method which is also recommended in Java Documents. How to write clone method By convention, the approach of writing clone method is: 1. Implements Cloneable interface This approach ensures your clone method can directly or indirectly call Object.clone(). Otherwise, calling Object.clone() will throws CloneNotSupportedException. Why we need to call Object.clone() in our clone method? Please see approach 2.2. 2. Override the clone method 2.1 Make the clone method to public method Please be noted that the clone method type of Object class is: protected Object clone() throws CloneNotSupportedException In order to support other class can use our clone method, we should define it as public method. 2.2 Call super.clone() to produce the new object By convention, the object returned by clone method should be obtained by calling super.clone (this means it’s better to produce the new object by super.clone() than directly use “new” operator). If a class and all of its superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass(). Key point: why we should use super.clone() to produce the new object instead of directly use “new” operator? v First of all, if all classes obey this convention, our clone method will directly or indirectly call Object.clone method. This method is a native method, it will be more efficient than directly “new” an object. v Secondly, Object.clone method can recognize the class type which called the clone method using RTTI mechanism. And it will return the new object which has the correct class type. For example: class A implements Cloneable class B extends A implements Cloneable { public Object clone() throws CloneNotSupportedException{ B b = null; b = (B) super.clone(); // It seems that super.clone() is //A.clone(), so it will return an //object of Class A. This is incorrect. //If the clone method of class A calls //super.clone method too, it will //return a new object belongs to //class B. Thus, we can cast it to //class B. This is the benefit of //Object.clone(). return b; } } Now, let’s consider another case, if we write clone method of class A like this: class A { public Object clone() { A a = null; a = new A(); // Then do some copy data operation. return a; } } When B.clone() calls super.clone(),unfortunately we can only get the object whose class is A. And we can’t cast the new object to class B since B is a subclass of A. That’s why it’s strongly recommended that clone method of all classes obey the convention that obtained the new object by calling super.clone(). 2.3 Clone members There are two cases: If the member supports clone, it’s better to call the clone method of the member to return a copy object of this member. If the member doesn’t support clone, you should create a new object which is the copy of the member. After this approach, it will be ensured that x.clone.equals(x) and x.clone() is independent with x. Examples /** * class B support clone * @author xzhu2 * */ class B implements Cloneable { private int intMember; public B(int i) { intMember = i; } public void setIntMember(int i) { intMember = i; } public Object clone() throws CloneNotSupportedException { B clonedObject = null; // Firstly, call super.clone to return new object clonedObject = (B)super.clone(); // Secondly, clone member here clonedObject.setIntMember(intMember); // The end, return new object return clonedObject; } } /** * class C doesn't support clone * @author xzhu2 * */ class C { private int intMember; public C(int i) { intMember = i; } public void setIntMember(int i) { intMember = i; } public int getIntMember() { return intMember; } } class A implements Cloneable { private int intMember = 0; private String stringMember = ""; private B supportCloneMember = null; private C notSupportCloneMember = null; public void setIntMember(int i) { intMember = i; } public void setStringMember(String s) { stringMember = s; } public void setB(B b) { supportCloneMember = b; } public void setC(C c) { notSupportCloneMember = c; } public Object clone() throws CloneNotSupportedException { A clonedObject = null; // Firstly, call super.clone to return new object clonedObject = (A)super.clone(); // Secondly, clone members here // For basic type member, directly set it to clonedObject // Because basic type parameter passes value. Modify // clonedObject.intMember can not effect the intMember // of itself. clonedObject.setIntMember(intMember); // For immutable member, directly set it to clonedObject. // Becasue we can not change the value of immutable // variable once it was setted. clonedObject.setStringMember(stringMember); // For member which support clone, we just clone it and // set the return object to the member of new object. B clonedB = (B)supportCloneMember.clone(); clonedObject.setB(clonedB); // For member which do not support clone, we need to create // new object. C clonedC = new C(notSupportCloneMember.getIntMember()); clonedObject.setC(clonedC); // The end, return new object return clonedObject; } } |
|
返回顶楼 | |
发表时间:2008-09-09
干嘛用英语??????好累啊,看了一般
|
|
返回顶楼 | |
发表时间:2008-09-10
引用 windshjw 昨天
A a1=new A(); A a2=new A(); a1.name="a1"; a2=a1; a2.name="a2"; System.out.println("a1.name="+a1.name); System.out.println("a2.name="+a2.name); result: a1.name=a2 a2.name=a2 Obviously, It is not correct. Pls confirm whether you copy error coding.The sentence "a2=(A)a1.clone();" should be used, instead "a2=a1;" i don't think so. My example is in the case: 除了在函数传值的时候是"引用传递",在任何用"="向对象变量赋值的时候都是"引用传递" not in clone |
|
返回顶楼 | |
发表时间:2008-09-10
引用 windshjw 昨天
Your deep clone coding is also not correct. The correct coding should be: public class A implements Cloneable { public String name; public String[] group = new String[2]; public Object clone() { A o = null; try { o = (A) super.clone(); o.group = (String[])group.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } } just you said ,it's wrong. thank you for kind reply |
|
返回顶楼 | |
发表时间:2008-11-17
序列化与反序列化 深度克隆
private static Object cloneObject(Object obj) throws Exception{ ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(obj); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in =new ObjectInputStream(byteIn); return in.readObject(); } |
|
返回顶楼 | |
浏览 16767 次