Wenn wir in Java ein Objekt kopieren müssen, gibt es zwei Arten von Kopien: Flache Kopie und tiefe Kopie.
Flache Kopie kopiert nur die Adresse des Quellobjekts. Wenn sich also der Wert des Quellobjekts ändert, ändert sich auch der Wert des kopierten Objekts.
Deep Copy kopiert alle Werte des Quellobjekts. Selbst wenn sich der Wert des Quellobjekts ändert, ändert sich der Wert des kopierten Objekts nicht.
Wir können den Konstruktor aufrufen, um eine tiefe Kopie durchzuführen. Wenn es sich um ein Objekt handelt, ist es neu .
Testfall
package com.lyj.demo.pojo.cloneTest; import lombok.Getter; /** * @author 凌兮 * @date 2021/4/15 14:28 * 通过构造器进行深拷贝测试 */ @Getter public class UserConstruct { private String userName; private AddressConstruct address; public UserConstruct() { } public UserConstruct(String userName, AddressConstruct address) { this.userName = userName; this.address = address; } public static void main(String[] args) { AddressConstruct address = new AddressConstruct("小区1", "小区2"); UserConstruct user = new UserConstruct("小李", address); // 调用构造函数进行深拷贝 UserConstruct copyUser = new UserConstruct(user.getUserName(), new AddressConstruct(address.getAddress1(), address.getAddress2())); // 修改源对象的值 user.getAddress().setAddress1("小区3"); // false System.out.println(user == copyUser); // false System.out.println(user.getAddress().getAddress1() == copyUser.getAddress().getAddress1()); // false System.out.println(user.getAddress().getAddress1().equals(copyUser.getAddress().getAddress1())); // true System.out.println(user.getAddress().getAddress2().equals(copyUser.getAddress().getAddress2())); } } package com.lyj.demo.pojo.cloneTest; import lombok.Getter; import lombok.Setter; /** * @author 凌兮 * @date 2021/4/15 14:28 */ @Getter @Setter public class AddressConstruct { private String address1; private String address2; public AddressConstruct() { } public AddressConstruct(String address1, String address2) { this.address1 = address1; this.address2 = address2; } }
Die übergeordnete Object-Klasse hat eine clone()-Kopiermethode, aber sie ist vom geschützten Typ, wir müssen sie neu schreiben und ändern Zum öffentlichen Typ muss die Unterklasse außerdem die klonbare Schnittstelle implementieren, um der JVM mitzuteilen, dass diese Klasse kopiert werden kann.
Testfall
package com.lyj.demo.pojo.cloneTest; import lombok.Getter; import lombok.Setter; /** * @author 凌兮 * @date 2021/4/15 14:49 * */ @Setter @Getter public class AddressClone implements Cloneable{ private String address1; private String address2; public AddressClone() { } public AddressClone(String address1, String address2) { this.address1 = address1; this.address2 = address2; } @Override protected AddressClone clone() throws CloneNotSupportedException { return (AddressClone) super.clone(); } } package com.lyj.demo.pojo.cloneTest; import lombok.Getter; import lombok.Setter; /** * @author 凌兮 * @date 2021/4/15 14:48 * 通过实现Clone接口实现深拷贝 */ @Setter @Getter public class UserClone implements Cloneable{ private String userName; private AddressClone address; public UserClone() { } public UserClone(String userName, AddressClone address) { this.userName = userName; this.address = address; } /** * Object父类有个clone()的拷贝方法,不过它是protected类型的, * 我们需要重写它并修改为public类型。除此之外, * 子类还需要实现Cloneable接口来告诉JVM这个类是可以拷贝的。 * @return * @throws CloneNotSupportedException */ @Override protected UserClone clone() throws CloneNotSupportedException { // 需要注意的是,super.clone()其实是浅拷贝, // 所以在重写UserClone类的clone()方法时,address对象需要调用address.clone()重新赋值 UserClone userClone = (UserClone) super.clone(); userClone.setAddress(this.address.clone()); return userClone; } public static void main(String[] args) throws CloneNotSupportedException { AddressClone address = new AddressClone("小区1", "小区2"); UserClone user = new UserClone("小李", address); UserClone copyUser = user.clone(); user.getAddress().setAddress1("小区3"); // false System.out.println(user == copyUser); // false System.out.println(user.getAddress().getAddress1().equals(copyUser.getAddress().getAddress1())); } }
Es ist zu beachten, dass super.clone() tatsächlich eine flache Kopie ist. Wenn Sie also die clone()-Methode der Benutzerklasse überschreiben, muss das Adressobjekt address.clone() aufrufen seinen Wert neu zuweisen.
Java bietet Serialisierungsfunktionen. Wir können das Quellobjekt zuerst serialisieren und es dann deserialisieren, um das Kopierobjekt zu generieren. Voraussetzung für die Verwendung der Serialisierung ist jedoch, dass die kopierte Klasse (einschließlich ihrer Mitgliedsvariablen) die Serializable-Schnittstelle implementieren muss.
Das Apache Commons Lang-Paket kapselt die Java-Serialisierung und wir können sie direkt verwenden.
Testfall
package com.lyj.demo.pojo.cloneTest; import lombok.Getter; import lombok.Setter; import java.io.Serializable; /** * @author 凌兮 * @date 2021/4/15 15:11 */ @Getter @Setter public class AddressSerializable implements Serializable { private String address1; private String address2; public AddressSerializable() { } public AddressSerializable(String address1, String address2) { this.address1 = address1; this.address2 = address2; } } package com.lyj.demo.pojo.cloneTest; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; /** * @author 凌兮 * @date 2021/4/15 15:10 * 通过Apache Commons Lang 序列化方式深拷贝 * Java提供了序列化的能力,我们可以先将源对象进行序列化,再反序列化生成拷贝对象。 * 但是,使用序列化的前提是拷贝的类(包括其成员变量)需要实现Serializable接口。 * Apache Commons Lang包对Java序列化进行了封装,我们可以直接使用它。 */ @Getter @Setter public class UserSerializable implements Serializable { private String userName; private AddressSerializable address; public UserSerializable() { } public UserSerializable(String userName, AddressSerializable address) { this.userName = userName; this.address = address; } public static void main(String[] args) { AddressSerializable address = new AddressSerializable("小区1", "小区2"); UserSerializable user = new UserSerializable("小李", address); UserSerializable copyUser = SerializationUtils.clone(user); user.getAddress().setAddress1("小区3"); // false System.out.println(user == copyUser); // false System.out.println(user.getAddress().getAddress1().equals(copyUser.getAddress().getAddress1())); } }
Gson kann Objekte in JSON serialisieren und JSON in Objekte deserialisieren, sodass wir es für Deep Copy verwenden können.
Testfall
package com.lyj.demo.pojo.cloneTest; import lombok.Data; /** * @author 凌兮 * @date 2021/4/15 15:31 */ @Data public class AddressGson { private String address1; private String address2; public AddressGson() { } public AddressGson(String address1, String address2) { this.address1 = address1; this.address2 = address2; } } package com.lyj.demo.pojo.cloneTest; import com.google.gson.Gson; import lombok.Data; /** * @author 凌兮 * @date 2021/4/15 15:30 * 使用Gson序列化方式进行深拷贝 * Gson可以将对象序列化成JSON,也可以将JSON反序列化成对象,所以我们可以用它进行深拷贝 */ @Data public class UserGson { private String userName; private AddressGson address; public UserGson() { } public UserGson(String userName, AddressGson address) { this.userName = userName; this.address = address; } public static void main(String[] args) { AddressGson address = new AddressGson("小区1", "小区2"); UserGson user = new UserGson("小李", address); // 使用Gson序列化进行深拷贝 Gson gson = new Gson(); UserGson copyUser = gson.fromJson(gson.toJson(user), UserGson.class); user.getAddress().setAddress1("小区3"); // false System.out.println(user == copyUser); // false System.out.println(user.getAddress().getAddress1().equals(copyUser.getAddress().getAddress1())); } }
Jackson ähnelt Gson und kann Objekte in JSON serialisieren. Der offensichtliche Unterschied besteht darin, dass die kopierte Klasse (einschließlich ihrer Mitgliedsvariablen) standardmäßig keinen Parameter haben muss Konstrukteur.
Testfälle re
package com.lyj.demo.pojo.cloneTest; import lombok.Data; /** * @author 凌兮 * @date 2021/4/15 15:41 */ @Data public class AddressJackson { private String address1; private String address2; public AddressJackson() { } public AddressJackson(String address1, String address2) { this.address1 = address1; this.address2 = address2; } } package com.lyj.demo.pojo.cloneTest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; /** * @author 凌兮 * @date 2021/4/15 15:40 * 通过Jackson方式实现深拷贝 * Jackson与Gson相似,可以将对象序列化成JSON,明显不同的地方是拷贝的类(包括其成员变量)需要有默认的无参构造函数。 */ @Data public class UserJackson { private String userName; private AddressJackson address; public UserJackson() { } public UserJackson(String userName, AddressJackson address) { this.userName = userName; this.address = address; } public static void main(String[] args) throws JsonProcessingException { AddressJackson address = new AddressJackson("小区1", "小区2"); UserJackson user = new UserJackson("小李", address); // 使用Jackson序列化进行深拷贝 ObjectMapper objectMapper = new ObjectMapper(); UserJackson copyUser = objectMapper.readValue(objectMapper.writeValueAsString(user), UserJackson.class); user.getAddress().setAddress1("小区3"); // false System.out.println(user == copyUser); // false System.out.println(user.getAddress().getAddress1().equals(copyUser.getAddress().getAddress1())); } }
Nachteile | ||
---|---|---|
1 Schlechte Benutzerfreundlichkeit, jedes Mal, wenn eine neue Mitgliedsvariable hinzugefügt wird, muss ein neuer Kopierkonstruktor hinzugefügt werden. ) Methode | 1. Die zugrunde liegende Implementierung ist relativ einfach 2. Es ist nicht erforderlich, Pakete von Drittanbietern einzuführen 3. Der Systemaufwand ist gering | 1 Die Benutzerfreundlichkeit ist schlecht, jedes Mal, wenn eine neue Mitgliedsvariable hinzugefügt wird, wird der Klon( )-Methode muss möglicherweise geändert werden 2. Kopieren Sie die Klasse (einschließlich ihrer Mitgliedsvariablen). Die klonbare Schnittstelle muss implementiert werden. |
Apache Commons Lang-Serialisierung | 1 | 1. Die zugrunde liegende Implementierung ist komplex. 2. Das Apache Commons Lang-JAR-Paket eines Drittanbieters muss eingeführt werden. 3. Das Kopieren einer Klasse (einschließlich ihrer Mitgliedsvariablen) muss die serialisierbare Schnittstelle implementieren. 4. Bei der Serialisierung entsteht ein gewisser Systemaufwand und Deserialisierung |
Gson-Serialisierung | 1. Hohe Benutzerfreundlichkeit, das Hinzufügen neuer Mitgliedsvariablen erfordert keine Änderung der Kopiermethode 2 und es sind keine zusätzlichen Schnittstellen und Methoden erforderlich Die zugrunde liegende Implementierung ist komplex. 2. Das Gson-JAR-Paket eines Drittanbieters muss eingeführt werden. 3. Es gibt einen gewissen Systemaufwand bei der Serialisierung und Deserialisierung. Starke Benutzerfreundlichkeit. Durch das Hinzufügen von Mitgliedsvariablen ist keine Änderung der Kopie erforderlich Methode | 1. Die zugrunde liegende Implementierung ist komplex. 2. Das JAR-Paket eines Drittanbieters muss eingeführt werden. 3. Beim Kopieren einer Klasse (einschließlich ihrer Mitgliedsvariablen) muss der Standardkonstruktor ohne Argumente implementiert werden. 4. Es gibt ein bestimmtes System Overhead bei der Serialisierung und Deserialisierung |
Das obige ist der detaillierte Inhalt vonWelche Methoden gibt es für Deep Copy in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!