Java的拷贝可以分为三种:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)。
在java中除了基本数据类型之外(int,long,short等),还存在引用数据类型,例如String以及对象实例。
对于基本数据类型,实际上是拷贝它的值,而对于引用数据类型,拷贝的就是它的引用,并没有创建一个新的对象,即没有分配新的内存空间。这样的拷贝就称作浅拷贝。
深拷贝就是在引用类型进行拷贝时,创建了新的对象,即分配了新的内存空间给拷贝对象。下面就来具体看看浅拷贝和深拷贝的区别
List浅拷贝
众所周知,list本质上是数组,而数组的是以地址的形式进行存储。
如上图将list A浅拷贝给list B,由于进行的是浅拷贝,所以直接将A的内容复制给了B,java中相同内容的数组指向同一地址,即进行浅拷贝后A与B指向同一地址。造成的后果就是,改变B的同时也会改变A,因为改变B就是改变B所指向地址的内容,由于A也指向同一地址,所以A与B一起改变。
几种浅拷贝
1、遍历循环复制
1 List<Person> destList=new ArrayList<Person>(srcList.size()); 2 for(Person p : srcList){ 3 destList.add(p); 4 }
2、使用List实现类的构造方法
List<Person> destList=new ArrayList<Person>(srcList);
3、使用list.addAll()方法
List<Person> destList=new ArrayList<Person>(); destList.addAll(srcList);
4、使用System.arraycopy()方法
1 Person[] srcPersons=srcList.toArray(new Person[0]); 2 Person[] destPersons=new Person[srcPersons.length]; 3 System.arraycopy(srcPersons, 0, destPersons, 0, srcPersons.length);
测试及结果
1 printList(destList); //打印未改变B之前的A 2 srcList.get(0).setAge(100);//改变B 3 printList(destList); //打印改变B后的A 4 //打印结果 5 123-->20 6 ABC-->21 7 abc-->22 8 123-->100 9 ABC-->21 10 abc-->22
List深拷贝
如图,深拷贝就是将A复制给B的同时,给B创建新的地址,再将地址A的内容传递到地址B。ListA与ListB内容一致,但是由于所指向的地址不同,所以改变相互不受影响。
深拷贝的方法
1.使用序列化方法
1 /** 2 * 对集合进行深拷贝 3 * 注意需要岁泛型类进行序列化(实现serializable) 4 * 5 * @param src 6 * @param <T> 7 * @return 8 * @throws IOException 9 * @throws ClassNotFoundException 10 */ 11 public static <T> List<T> deepCopy(List<T> src) { 12 try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 13 ObjectOutputStream outputStream = new ObjectOutputStream(byteOut); 14 ) { 15 outputStream.writeObject(src); 16 try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); 17 ObjectInputStream inputStream = new ObjectInputStream(byteIn); 18 ) { 19 return (List<T>) inputStream.readObject(); 20 } 21 } catch (Exception e) { 22 ThrowableUtils.getString(e); 23 } 24 return Collections.emptyList(); 25 }
2.clone方法
1 public class A implements Cloneable { 2 public String name[]; 3 public A(){ name=new String[2]; } 4 public Object clone() { 5 A o = null; 6 try { 7 o = (A) super.clone(); 8 } catch (CloneNotSupportedException e) { 9 e.printStackTrace(); 10 } return o; 11 } 12 } 13 14 for(int i=0;i<n;i+=){ 15 copy.add((A)src.get(i).clone()); 16 }
Java对对象和基本的数据类型的处理是不一样的。在Java中用对象的作为入口参数的传递则缺省为”引用传递”,也就是说仅仅传递了对象的一个”引用”,这个”引用”的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。 除了在函数传值的时候是”引用传递”,在任何用”=”向对象变量赋值的时候都是”引用传递”。
测试及结果
原文地址:https://www.cnblogs.com/zt007/p/9884712.html
时间: 2024-10-13 16:32:42