浅复制值与深复制

229 阅读3分钟

浅拷贝

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

Student student1 =new Student();  
student1.setAge(23);    
student1.setName("liqitian3344");    
Student student3 = student1;    
System.out.println(student1);    
System.out.println(student3);    
//结果如下    
Student(age=23, name=liqitian3344)    
Student(age=23, name=liqitian3344)

这样大致看一下也像是那么回事,看下面
Student student1 =new Student();    
student1.setAge(23);    
student1.setName("liqitian3344");    
Student student3 = student1;    
//这里 操作了一下 student3,student1.setAge(100); 也能达到同样的效果    
student3.setAge(100);    
System.out.println(student1);    
System.out.println(student3);

能看出 这种方式只是把Student的引用student1拷贝一份student3,他们指向的是同一个new Student(),所以这种方式达不到浅赋值的程度。

总所周知,java要实现对象复制,预复制对象要实现Cloneable接口并重写clone方法(见实例类Student),该接口是个标志接口源码如下

public interface Cloneable {}

再看一种情况(浅复制)

Student student1 = new Student();   
student1.setAge(23);    
student1.setName("liqitian3344");            
Student student2 = (Student) student1.clone();    
student2.setAge(80);    
System.out.println(student1);    
System.out.println(student2);    
String result = student1.getName() == student2.getName()    ? "浅" : "深";    
System.out.println(result);        
//结果    
Student(age=23, name=liqitian3344)    
Student(age=80, name=liqitian3344)    
浅

嗯 这个看起来像是那么回事,下面看个不像那么回事的

新实例类如下

@Data
class Student implements Cloneable {    
  private int age;    
  private String name;    
  private Book book;    
  @Override    
  protected Object clone() throws CloneNotSupportedException {
        return super.clone();    
  }
  }
@Data
class Book{    
 private String bookName;
}

在写段代码测一下

Book book = new Book();   
book.setBookName("语文");     
Student student1 = new Student();   
student1.setAge(23);    
student1.setName("liqitian3344");   
student1.setBook(book);     
Student student2 = (Student) student1.clone();    
student2.setAge(100);    
book.setBookName("数学");    
System.out.println(student1);    
System.out.println(student2);     
String result = student1.getName() == student2.getName()  ? "clone是浅拷贝的" : "clone是深拷贝的";     
System.out.println(result);    
//结果如下    
Student(age=23, name=liqitian3344, book=Book(bookName=数学))    
Student(age=100, name=liqitian3344, book=Book(bookName=数学))    
clone是浅拷贝的

好了 浅赋值结论:会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

深拷贝就没什么好说的了,记住上面的概念就好,深拷贝的实现方式有两种

1. 继续使用clone();方法就是在上面Student中clone()方法重写成下面的样子

@Data
class Student implements Cloneable {    
private int age;    
private String name;    
private Book book;     
@Override    
protected Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        book = (Book) book.clone();        
        return student;    }
}

测试代码同上

2. 序列化实现对象深拷贝,下面直接代码了

//将对象写入流中
Student student1 = new Student();
ByteArrayOutoutStream bo=new ByteArrayOutputStream();  
 ObjectOutputStream oo=new ObjectOutputStream(bo);   
oo.writeObject(student1);  
//从流里读出  
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());   
ObjectInputStream oi=new ObjectInputStream(bi);   
return(oi.readObject());