Object copying is basically a rigid requirement when we write code every day, and we often encounter it, but many people are busy writing business every day, ignoring some detailed problems and understanding. Sometimes once there is a problem in this area, it is not easy to troubleshoot Up.
So this article will sort out.
Note: This article has been included in the Github open source project: github.com/hansonwang99/JavaCollection . There are detailed self-learning programming learning routes, interview questions and interviews , programming materials and series of technical articles, etc. The resources are continuously updated...
”
Value type vs reference type
The accurate distinction between these two concepts is very important for the understanding of deep and shallow copy problems.
As the title of the second chapter of Java
" Java
Programming Thoughts" in the Bible says, Java
everything can be regarded as an object!
So in Java
the world we have come to , we have to get used to using references to manipulate objects. Among them Java
, such as arrays, classes Class
, enumerations Enum
, Integer
packaging classes, etc., are typical reference types, so in general, the method of passing by reference is used when operating ;
However Java
, language-level basic data types, such as int
these basic types, are generally operated by value transfer , so they are sometimes called value types.
In order to facilitate the following descriptions and examples, we first define two categories: Student
and Major
, which represent "students" and "professionals" respectively. The two are inclusive relationships:
// 学生的所学专业
public class Major {
private String majorName; // 专业名称
private long majorId; // 专业代号
// ... 其他省略 ...
}
// 学生
public class Student {
private String name; // 姓名
private int age; // 年龄
private Major major; // 所学专业
// ... 其他省略 ...
}
Assignment vs. shallow copy vs. deep copy
Object assignment
Assignment is the most common operation in the daily programming process, the simplest such as:
Student codeSheep = new Student();
Student codePig = codeSheep;
Strictly speaking, this cannot be regarded as an object copy, because the copy is only the reference relationship, and does not generate a new actual object:
Shallow copy
Shallow copy is a type of object cloning, and its important characteristics are reflected in the word "shallow" .
For example, we try to studen1
copy through examples. student2
If it is a shallow copy, the rough model can be shown as follows:
Obviously, the value type field will be copied, and the reference type field will only copy the reference address, and the actual object space pointed to by the reference address is actually only one copy.
A picture is better than the preface, I think the above picture has been very clear.
Deep copy
Deep copy is compared to the shallow copy shown above, except that the value type field will be copied, and the object pointed to by the reference type field will also be created in memory , just like this:
The principle is very clear, let's take a look at the specific code implementation.
Shallow copy code implementation
In the above example, I want to get it by student1
copying student2
. The typical implementation of shallow copy is: let the class of the copied object implement the Cloneable
interface and rewrite the clone()
method.
Take the above Student
class copy as an example:
public class Student implements Cloneable {
private String name; // 姓名
private int age; // 年龄
private Major major; // 所学专业
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
// ... 其他省略 ...
}
Then we write a test code, you will know after a try:
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Major m = new Major("计算机科学与技术",666666);
Student student1 = new Student( "CodeSheep", 18, m );
// 由 student1 拷贝得到 student2
Student student2 = (Student) student1.clone();
System.out.println( student1 == student2 );
System.out.println( student1 );
System.out.println( student2 );
System.out.println( "\n" );
// 修改student1的值类型字段
student1.setAge( 35 );
// 修改student1的引用类型字段
m.setMajorName( "电子信息工程" );
m.setMajorId( 888888 );
System.out.println( student1 );
System.out.println( student2 );
}
}
Run and get the following results:
It can be seen from the results:
student1==student2
Print false, indicating that theclone()
method has indeed cloned a new object;Modifying the value type field does not affect the new cloned object, which is in line with expectations;
The
student1
internal reference object is modified , and the cloned objectstudent2
is also affected, indicating that the internal is still connected.
Deep copy code implementation
Deep traversal copy
Although the clone()
method can complete the copying of the object, note that the clone()
method defaults to a shallow copy behavior, just like the example above. If you want to implement a deep copy, you need to override the clone()
method to implement a deep traversal copy of the referenced object and perform a carpet search.
So for the above example, if you want to implement deep copy, you first need to Major
transform the deeper reference class , let it also implement the Cloneable
interface and rewrite the clone()
method:
public class Major implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// ... 其他省略 ...
}
Secondly, we also need to rewrite the method in the top-level calling class clone
to call the clone()
method of the reference type field to achieve deep copy. Corresponding to this article, it is the Student
class:
public class Student implements Cloneable {
@Override
public Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.major = (Major) major.clone(); // 重要!!!
return student;
}
// ... 其他省略 ...
}
At this time, the above test case is unchanged, and the results can be obtained by running:
Obviously, at this time student1
and the student2
two objects are completely independent, free from mutual interference.
Use deserialization to achieve deep copy
I remember that in the previous article "Serialization/Deserialization, I have to bear you for a long time", I have sorted out and summarized the knowledge points of "serialization and deserialization" in detail.
Using deserialization technology, we can also deep copy from one object to another copy object, and this product is surprisingly effective in solving the problem of deep copying of multi-layer dolls.
So let's modify the Student
class here and let its clone()
method generate a deep copy of the original object through serialization and deserialization:
public class Student implements Serializable {
private String name; // 姓名
private int age; // 年龄
private Major major; // 所学专业
public Student clone() {
try {
// 将对象本身序列化到字节流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream =
new ObjectOutputStream( byteArrayOutputStream );
objectOutputStream.writeObject( this );
// 再将字节流通过反序列化方式得到对象副本
ObjectInputStream objectInputStream =
new ObjectInputStream( new ByteArrayInputStream( byteArrayOutputStream.toByteArray() ) );
return (Student) objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
// ... 其他省略 ...
}
Of course, in this case, the referenced subclass (such as the Major
class here ) must also be serializable, that is, it implements the Serializable
interface:
public class Major implements Serializable {
// ... 其他省略 ...
}
At this time, the test case is completely unchanged. If you run it directly, you can also get the following results:
Obviously, this time student1
and the student2
two objects are also completely independent, without mutual interference, and the deep copy is completed.
postscript
Well, let's talk about the issue of "deep copy" and "shallow copy" this time. I thought that this article would be finished soon, but I pulled out so many things, but after sorting out and connecting in this way, I still feel a lot clearer.
—————END—————
Friends who like this article, welcome to follow the official account programmer Xiaohui , and watch more exciting content
点个[在看],是对小灰最大的支持!