大家都知道java里面分为浅拷贝和深拷贝。举个简单的例子,区分一下浅拷贝和深拷贝的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class Address{ private String address; public Address(String address){ this .address = address; } public String getAddress(){ return address; } public void setAddress(String address){ this .address = address; } @Override protected Object clone() { Address address = null ; try { address = (Address) super .clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return address; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public class Student implements Cloneable{ private String name; public List<Address> addressList; public Student(){ } public Student(String name) { this .name = name; } public void setName(String name){ this .name = name; } public String getName() { return name; } @Override protected Object clone() { Student student = null ; try { student = (Student) super .clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return student; } } |
先创建两个类,一个是地址,一个是学生,便于后边的打印结果能明显区分浅拷贝和深拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class myClass { public static void main(String[] args) { Student student = new Student( "李晓东" ); Student student2 = (Student) student.clone(); println(student.getName() ); println(student2.getName() ); println( "改变student2的姓名后--------------" ); student2.setName( "张天" ); println(student.getName() ); println(student2.getName()); } public static void println(String str) { System.out.println(str); } } |
打印结果如下
1 2 3 4 5 | 李晓东 李晓东 改变student2的姓名后-------------- 李晓东 张天 |
可以看到当我们改变student2的name值的时候,并没有改变student的name值(String在此时不属于引用值类型)
在我们的项目当中,经常会遇到一个类里面有List,然后List装载另外一个对象,这个时候要进行深拷贝就需要用到如下的办法,先把Address进行序列化和实现cloneable接口并且重写clone方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class Address implements Cloneable,Serializable{ private String address; public Address(String address){ this .address = address; } public String getAddress(){ return address; } public void setAddress(String address){ this .address = address; } @Override protected Object clone() { Address address = null ; try { address = (Address) super .clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return address; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | public class myClass { public static void main(String[] args) { List<Address> addressList = new ArrayList<>(); addressList.add( new Address( "北京市" )); Student student = new Student( "李晓东" ); student.addressList = addressList; Student student2 = (Student) student.clone(); student2.addressList = depCopy2(addressList); println(student.getName() + "---" + student.addressList.get( 0 ).getAddress()); println(student2.getName() + "---" + student2.addressList.get( 0 ).getAddress()); println( "改变student2的姓名后--------------" ); student2.setName( "张天" ); student2.addressList.get( 0 ).setAddress( "湖南省" ); println(student.getName() + "---" + student.addressList.get( 0 ).getAddress()); println(student2.getName() + "---" + student2.addressList.get( 0 ).getAddress()); } public static void println(String str) { System.out.println(str); } /*** * 方法二 * 需要Address实现cloneable接口和重写clone方法,次方法有限制性, * 例如要先声明List是保存的什么对象,并且当碰到对象里面还持有List集合的时候 * 就不管用的,所以建议使用第一种方法 * * @param addresses * @return */ public static List<Address> depCopy2(List<Address> addresses) { List<Address> destList = new ArrayList<>(); for (Address address : addresses) { destList.add((Address) address.clone()); } return destList; } /*** * 方法一对集合进行深拷贝 注意需要对泛型类进行序列化(实现Serializable) * * @param srcList * @param <T> * @return */ public static <T> List<T> depCopy(List<T> srcList) { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); try { ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(srcList); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream inStream = new ObjectInputStream(byteIn); List<T> destList = (List<T>) inStream.readObject(); return destList; } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } } |
此时打印结果是
1 2 3 4 5 | 李晓东---北京市 李晓东---北京市 改变student2的姓名后-------------- 李晓东---北京市 张天---湖南省 |
如果没看明白,可以自己修改不实现cloneable接口和注释掉clone方法再执行看结果,一定要自己写自己试,这样才会印象深刻!!!