1、如果一个类没有实现Cloneable接口,直接调用clone()方法,会报异常CloneNotSupportedException,这一点已经在Object源码中写道:
* @return a clone of this instance. * @exception CloneNotSupportedException if the object's class does not * support the {@code Cloneable} interface. Subclasses * that override the {@code clone} method can also * throw this exception to indicate that an instance cannot * be cloned. * @see java.lang.Cloneable */ protected native Object clone() throws CloneNotSupportedException;
而且,源码也写到Object的clone()方法是浅拷贝的,这一点在之前的Object源码分析中我已经写过了.
2、自定义类实现深拷贝方法有2种,下面依次给出具体写法。
2.1、自定义类要实现Cloneable接口,并覆写clone()方法。
/** * 深拷贝和浅拷贝的测试 */ //测试类1 class Person implements Cloneable{ String name; int age; Person(String name,int age){ this.name=name; this.age=age; } @Override public Object clone() { try{ return super.clone(); }catch(CloneNotSupportedException e){ return null; } } } //测试类2 class Animal implements Cloneable{ Person host;//主人 int age;//年纪 Animal(Person person,int age){ this.host=person; this.age=age; } @Override public Object clone(){ try{ Animal animal=(Animal) super.clone(); animal.host=(Person)host.clone();//深拷贝处理 return animal; }catch (CloneNotSupportedException e){ return null; } } } //测试 public class Main{ public static void main(String[] args) { Person person1=new Person("cxh",26); Person person2=(Person)person1.clone(); System.out.println("----------------浅拷贝--------------"); //测试Object的clone方法为浅拷贝 //String类用==测试内存地址是否一致 System.out.println("person1和person2的name内存地址是否相同:"+(person1.name==person2.name)); System.out.println("----------------深拷贝--------------"); //重写Object的clone方法,实现深拷贝 //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝 Animal animal1=new Animal(new Person("cxh",26),3); Animal animal2=(Animal) animal1.clone(); System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host)); } }
输出:----------------浅拷贝-------------- person1和person2的name内存地址是否相同:true ----------------深拷贝-------------- animal1和animal2的host内存地址是否相同:false Process finished with exit code 0
一个讲解很详细的博客:http://blog.csdn.net/zhangjg_blog/article/details/18369201
2.2、通过序列化方式实现深拷贝:先将要拷贝对象写入到内存中的字节流中,然后再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,那么这个新对象和原对象就不存在任何地址上的共享,自然实现了深拷贝。
自定义类需要实现Serializable接口。
import java.io.*; /** * 深拷贝和浅拷贝的测试 * 如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中,再从字节流中将其读出来, * 这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。 */ //工具类 class CloneUtil{ public static <T extends Serializable> T clone(T obj){ T cloneObj=null; try{ //写入字节流 ByteArrayOutputStream baos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(baos); oos.writeObject(obj); oos.close(); //分配内存,写入原始对象,生成新对象 ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());//获取上面的输出字节流 ObjectInputStream ois=new ObjectInputStream(bais); //返回生成的新对象 cloneObj=(T)ois.readObject(); ois.close(); }catch (Exception e){ e.printStackTrace(); } return cloneObj; } } //测试类1 class Person implements Serializable{ String name; int age; Person(String name,int age){ this.name=name; this.age=age; } } //测试类2 class Animal implements Serializable{ Person host;//主人 int age;//年纪 Animal(Person person,int age){ this.host=person; this.age=age; } } //测试 public class Main{ public static void main(String[] args) { System.out.println("----------------深拷贝--------------"); //重写Object的clone方法,实现深拷贝 //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝 Animal animal1=new Animal(new Person("cxh",26),3); Animal animal2=CloneUtil.clone(animal1); System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host)); } }
输出结果:
----------------深拷贝-------------- animal1和animal2的host内存地址是否相同:false
参考博客:http://blog.csdn.net/chenssy/article/details/12952063