JAVA - copie profonde de l'objet

Hériter de l'interface Cloneable et réimplémenter la méthode de clonage

La classe d'entité doit hériter de l'interface Cloneable et réimplémenter la méthode clone() .
Il convient de noter que les éléments de type pointeur référencés dans la classe d'entité héritent également de l'interface Cloneable et réimplémentent la méthode clone(), ou créent un nouvel objet et l'affectent à l'élément.

@Data
public class CloneableEntity implements Cloneable{
    
    
    private String stringValue;
    private PointerEntity pointerEntity;
    private List<String> listValue=  new ArrayList<>();

    //填充列表 用来比较克隆效率
    public void initListValue() {
    
    
        for (int i = 0; i < 10000; i++) {
    
    
            this.listValue.add(UUID.randomUUID().toString());
        }
    }

    @Override
    public CloneableEntity clone() throws CloneNotSupportedException {
    
    
        CloneableEntity clone = (CloneableEntity)super.clone();
		// 指针类型的元素要做clone一份新的
		if(null!=this.pointerEntity) {
    
    
        	clone.setPointerEntity(this.pointerEntity.clone());
        }
        // 创建一个新的对象给元素
        clone.setListValue(new ArrayList<>(listValue));
        return clone;
    }
}
@Data
public class PointerEntity implements Cloneable{
    
    
    private String uuid;

    public PointerEntity(){
    
    
    }

    public PointerEntity(String uuid){
    
    
        this.uuid = uuid;
    }

    @Override
    protected PointerEntity clone() throws CloneNotSupportedException {
    
    
        return (PointerEntity)super.clone();
    }
}

instance de clonage

Toute modification des éléments du nouvel objet cloné n'affectera pas la valeur des éléments de l'objet d'origine.

Gson gson = new Gson();//用来打印对象
//        Cloneable 深拷贝
CloneableEntity entity1 = new CloneableEntity();
entity1.setStringValue("1");
entity1.setPointerEntity(new PointerEntity(UUID.randomUUID().toString()));
entity1.setListValue(new ArrayList<String>(){
    
    {
    
    add("1");add("2");}});
CloneableEntity clone1 = entity1.clone();
//对克隆后的对象进行修改
clone1.setStringValue("1--1");
clone1.getListValue().add("3");
clone1.getPointerEntity().setUuid(UUID.randomUUID().toString());
System.out.println("entity1: "+gson.toJson(entity1));
System.out.println("clone1: "+gson.toJson(clone1));
-------------------------------
entity1: {
    
    "stringValue":"1","pointerEntity":{
    
    "uuid":"27bb47c6-1ad3-4b79-a408-509f2163b5fa"},"listValue":["1","2"]}
clone1: {
    
    "stringValue":"1--1","pointerEntity":{
    
    "uuid":"a3495d1d-e32c-4dee-be57-0a8a3f30678c"},"listValue":["1","2","3"]}

Sérialisation et désérialisation à l'aide de flux

La classe clonée doit prendre en charge la sérialisation et les éléments de la classe doivent également prendre en charge la sérialisation. Sinon, une exception qui ne prend pas en charge la sérialisation apparaîtra lors du clonage.

@Data
public class Serialzable2Entity implements Serializable {
    
    
    private String stringValue;
    private SerialzablePointerEntity pointerEntity;
    private List<String> listValue=  new ArrayList<>();

    //填充列表 用来比较克隆效率
    public void initListValue() {
    
    
        for (int i = 0; i < 10000; i++) {
    
    
            this.listValue.add(UUID.randomUUID().toString());
        }
    }
}
@Data
public class SerialzablePointerEntity implements Serializable {
    
    
    private String uuid;
    public SerialzablePointerEntity(){
    
    
    }

    public SerialzablePointerEntity(String uuid){
    
    
        this.uuid = uuid;
    }

}

instance de clonage

Gson gson = new Gson();//用来打印对象
//流深拷贝
Serialzable2Entity entity4 = new Serialzable2Entity();
entity4.setStringValue("41");
entity4.setPointerEntity(new SerialzablePointerEntity(UUID.randomUUID().toString()));
entity4.setListValue(new ArrayList<String>(){
    
    {
    
    add("41");add("42");}});
Serialzable2Entity clone4 ;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(bos);
) {
    
    
 oos.writeObject(entity4);
 oos.flush();
 try (
      ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bis);
 ) {
    
    
     clone4 = (Serialzable2Entity) ois.readObject();
 }
}
clone4.setStringValue("41--1");
clone4.getListValue().add("43");
clone4.getPointerEntity().setUuid(UUID.randomUUID().toString());
System.out.println("entity4: " + gson.toJson(entity4));
System.out.println("clone4: " + gson.toJson(clone4));
---------------------------------------
entity4: {
    
    "stringValue":"41","pointerEntity":{
    
    "uuid":"af3c287f-1289-4fb3-947f-f5b7684ef07e"},"listValue":["41","42"]}
clone4: {
    
    "stringValue":"41--1","pointerEntity":{
    
    "uuid":"0549e071-d7df-469f-baae-578e9aa89194"},"listValue":["41","42","43"]}

Utilisation du sérialiseur Apache Commons Lang

Apache Commons Lang est livré avec une classe d'outils de sérialisation SerializationUtils , dans laquelle la méthode clone() nous permet de faire une copie complète de l'objet.
En fait, son principe est le même que la sérialisation et la désérialisation du flux ci-dessus, sauf qu'il contient davantage de conversions de types et d'autres opérations. Par conséquent, il
faut également que la classe clonée prenne en charge la sérialisation et que les éléments de la classe prennent également en charge la sérialisation. Sinon, une exception qui ne prend pas en charge la sérialisation apparaîtra lors du clonage.

instance de clonage

Gson gson = new Gson();//用来打印对象
// Apache Commons Lang序列化深拷贝 拷贝对象和对象中所有涉及到的指针类型的对象都要实现序列化
Serialzable2Entity entity2 = new Serialzable2Entity();
entity2.setStringValue("11");
entity2.setPointerEntity(new SerialzablePointerEntity(UUID.randomUUID().toString()));
entity2.setListValue(new ArrayList<String>(){
    
    {
    
    add("11");add("12");}});
Serialzable2Entity clone2 = SerializationUtils.clone(entity2);
//对克隆后的对象进行修改
clone2.setStringValue("11--1");
clone2.getListValue().add("13--1");
clone2.getPointerEntity().setUuid(UUID.randomUUID().toString());
System.out.println("entity2: "+gson.toJson(entity2));
System.out.println("clone2: "+gson.toJson(clone2));
------------------------------------------
entity2: {
    
    "stringValue":"11","pointerEntity":{
    
    "uuid":"303e0bff-ad81-4b56-a1db-311cf894b189"},"listValue":["11","12"]}
clone2: {
    
    "stringValue":"11--1","pointerEntity":{
    
    "uuid":"bb42fd5b-d0ce-483a-9f34-d32e1b0eab5c"},"listValue":["11","12","13--1"]}

Utilisez Gson pour sérialiser et désérialiser

Utilisez la sérialisation et la désérialisation Gson pour cloner, et l'objet cloné n'a pas besoin d'extensions.

@Data
public class NormalEntity{
    
    
    private String stringValue;
    private NormalPointerEntity pointerEntity;
    private List<String> listValue=  new ArrayList<>();

    /**
     * 初始化列表
     */
    public void initListValue() {
    
    
        for (int i = 0; i < 10000; i++) {
    
    
            this.listValue.add(UUID.randomUUID().toString());
        }
    }
}

@Data
public class NormalPointerEntity{
    
    
    private String uuid;

    public NormalPointerEntity(){
    
    
    }

    public NormalPointerEntity(String uuid){
    
    
        this.uuid = uuid;
    }
}
Gson gson = new Gson();
// Gson 序列化反序列化深拷贝 对对象没有要求
NormalEntity entity3 = new NormalEntity();
entity3.setStringValue("21");
entity3.setPointerEntity(new NormalPointerEntity(UUID.randomUUID().toString()));
entity3.setListValue(new ArrayList<String>(){
    
    {
    
    add("21");add("22");}});
NormalEntity clone3 = gson.fromJson(gson.toJson(entity3 ), NormalEntity.class);
//修改克隆后的对象
clone3.setStringValue("21--1");
clone3.getListValue().add("23");
clone3.getPointerEntity().setUuid(UUID.randomUUID().toString());
System.out.println("entity3: "+gson.toJson(entity3));
System.out.println("clone3: "+gson.toJson(clone3));
---------------------------
entity3: {
    
    "stringValue":"21","pointerEntity":{
    
    "uuid":"b81d7ee9-54db-4d51-b09d-0a61adce4518"},"listValue":["21","22"]}
clone3: {
    
    "stringValue":"21--1","pointerEntity":{
    
    "uuid":"276de4f8-0b23-4435-9225-dfc836311064"},"listValue":["21","22","23"]}

Comparez le pour et le contre

Tout d'abord, nous comparons l'efficacité


StopWatch stopWatch = new StopWatch();
//        Cloneable 深拷贝
CloneableEntity entity1 = new CloneableEntity();
entity1.initListValue();
stopWatch.start("Cloneable 深拷贝");
CloneableEntity clone1 = entity1.clone();
stopWatch.stop();

//        流深拷贝
Serialzable2Entity entity4 = new Serialzable2Entity();
entity4.initListValue();
Serialzable2Entity clone4 ;
stopWatch.start(" 流深拷贝");
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(bos);
) {
    
    
    oos.writeObject(entity4);
    oos.flush();
    try (
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
    ) {
    
    
        clone4 = (Serialzable2Entity) ois.readObject();
    }
}
stopWatch.stop();

//        Apache Commons Lang序列化深拷贝 拷贝对象和对象中所有涉及到的指针类型的对象都要实现序列化
Serialzable2Entity entity2 = new Serialzable2Entity();
entity2.initListValue();
stopWatch.start("Apache Commons Lang序列化深拷贝");
Serialzable2Entity clone2 = SerializationUtils.clone(entity2);
stopWatch.stop();

//        Gson 序列化反序列化深拷贝 对对象没有要求
NormalEntity entity3 = new NormalEntity();
entity3.initListValue();
stopWatch.start(" Gson 序列化反序列化深拷贝");
Gson gson = new Gson();//用来打印对象
NormalEntity clone3 = gson.fromJson(gson.toJson(entity3 ), NormalEntity.class);
stopWatch.stop();

System.out.println(stopWatch.prettyPrint());
-----------------------------------
---------------------------------------------
ns         %     Task name
---------------------------------------------
000029100  000%  Cloneable 深拷贝
048922700  023%  流深拷贝
017047500  008%  Apache Commons Lang序列化深拷贝
150727000  070%  Gson 序列化反序列化深拷贝

Selon la consommation de temps, on peut voir que le clonage en héritant de l'interface Cloneable est le plus efficace, suivi par la sérialisation de flux et SerializationUtils , et la sérialisation Gson est la plus lente.
Il convient de noter que l'efficacité de la copie en profondeur en continu et de SerializationUtils devrait en fait être similaire. Parce que pratiquement tous les flux sont utilisés pour la sérialisation et la désérialisation. Cependant, étant donné qu'une partie du temps est consommée lorsque la classe IO est chargée pour la première fois après le démarrage du programme, lors de l'exécution du clonage SerializationUtils , la consommation de temps est plus courte que la sérialisation de flux.
Lorsque nous échangeons l'ordre d'exécution de la sérialisation de flux et de SerializationUtils , nous constatons que le temps consommé par la sérialisation de flux est plus court que celui de SerializationUtils .

Résumé des avantages et des inconvénients

méthode Avantage désavantage
Hériter de l'interface Cloneable Haute efficacité, pas besoin de se référer à d'autres packages de bocaux et faible surcharge du système La classe clonée doit réécrire l'interface Cloneable, choisir de cloner manuellement les éléments de pointeur dans la classe, et lorsque les champs de la classe sont mis à jour, nous devons également mettre à jour la méthode clone à temps pour éviter l'échec de copie profonde
sérialisation de flux Il n'est pas nécessaire de se référer à d'autres packages jar, et il n'est pas nécessaire d'ajuster le code pour ajouter et modifier des champs L'efficacité est moyenne, la classe doit prendre en charge la sérialisation et le processus de sérialisation et de désérialisation a une surcharge système importante
SerializationUtils.clone() Le code est concis et facile à utiliser, l'ajout et la modification de champs n'ont pas besoin d'ajuster le code L'efficacité est moyenne, le package apache common jar doit être introduit, la classe doit prendre en charge la sérialisation et le processus de sérialisation et de désérialisation a une surcharge système importante
Sérialisation Gson Ne nécessite aucun prétraitement de la classe L'efficacité est très faible, le package jar doit être introduit et le processus de sérialisation et de désérialisation a une surcharge système importante

Guess you like

Origin blog.csdn.net/qq_40096897/article/details/130700014