标签:
今天看到原型法模式,就顺便先学了下Java的Cloneable接口,这个东西是个标记接口,里面什么都没有。我又找了Object中的clone方法,这个方法被声明为propected类型,但是在B类中new了一个A类的对象a,a却不能调用a.clone()方法。而在B类的对象b却可以调用clone方法b.clone();一开始没明白是怎么回事,后来一想A,B的父类虽然都是Object,但是毕竟是不同的父亲,ObjectA和A又不在一个包里面,而且它是A的父类,那么当然只能在ObjectA的子类A中使用子类没有重写的方法。
接着往下走,虽然Object中有clone()方法,但是直接在A类中使用此方法会出现CloneNotSupportedException错误。直接看API,它大体意思是这样的:Object中的clone()方法是实现特定的复制操作,比如数组(因为数组均已经模式实现了这个接口),其它的类如果想要调用clone()方法就需要实现Cloneable接口。
最后再说一下浅复制和深复制,在Java中,可以这么理解,浅复制就是复制了一份引用,而深复制就是复制了引用指代的对象,显然,我们所要的clone()方法要达到深复制的效果,因为复制引用显然是没必要费这么大劲的。
首先我们来看看浅复制,在这里我们有三个类,一个测试类Test,一个类A,一个Index类。具体代码如下:
A类中有一个String类型的name属性,外加一个Index对象类型的属性。
public class A implements Cloneable{ String name; Index b; public int getIndex() { return b.getIndex(); } public Index index(){ return b; } public void setIndex(Index b) { this.b = b; } public String getName() { return name; } public void setName(String name) { this.name = name; } public A clone() throws CloneNotSupportedException{ return (A) super.clone(); } }
Index类中有设置索引大小的方法和属性
public class Index { public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } int index; }
测试类:
public class Test { public static void main(String[] args) throws CloneNotSupportedException { A a = new A(); a.setName("A"); Index index = new Index(); index.setIndex(0); a.setIndex(index); System.out.println(a.getName());//A System.out.println(a.getIndex());//0 System.out.println("复制了一份a"); A b = a.clone(); System.out.println("修改b之前的属性"); System.out.println(b.getName());//A System.out.println(b.getIndex());//0 b.setName("B"); index.setIndex(999); b.setIndex(index); System.out.println("修改b之后的属性"); System.out.println(b.getName());//B System.out.println(b.getIndex());//999 System.out.println("修改完b之后查看a对象中的属性"); System.out.println(a.getName());//A System.out.println(a.getIndex());//999 System.out.println(b.index().equals(a.index()));//true } }
上面就是浅复制,在复制的时候并木有完全将对象内容复制一遍,对象中的引用类型的属性只是复制了引用而已。
改成深复制为:则在Index中同样要实现Cloneable接口,且在A类的clone()方法中添加:
public A clone() throws CloneNotSupportedException{ b = b.clone(); return (A) super.clone(); } //同样的Test类测试结果为: A 0 复制了一份a 修改b之前的属性 A 0 修改b之后的属性 B 999 修改完b之后查看a对象中的属性 A 0 False
所以,如果我们所要克隆复制的对象中有引用对象存在的时候,一定要注意深复制的问题。
标签:
原文地址:http://www.cnblogs.com/zhangxd-stn/p/roomy_java_0.html