[Java] Tres formas de implementar la clonación de objetos (interfaz clonable, serialización Java, serialización FastJson)

Prefacio

Hay dos formas comunes de crear objetos: nuevos y clonados.

Cuando el proceso de creación de un objeto es complicado, podemos clonar un objeto existente directamente sin tener que ocuparnos de los detalles de la creación (modo prototipo).

1. Implemente la interfaz clonable y vuelva a escribir el método de clonación

El método de clonación predeterminado de Object es en realidad una copia simple del campo y, para tipos de datos simples, es una copia del valor;

Para tipos complejos de campos, es una copia de la dirección del puntero, y el objeto clonado y el objeto original apuntan a un espacio de direcciones.

Entonces, el método de clonación predeterminado es la clonación superficial . Comprobémoslo con el siguiente ejemplo:

package com.dl.JavaBase;

class Car implements Cloneable{
    
    
    private String brand;//品牌
    private int maxSpeed;//最高时速

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

    @Override
    public String toString() {
    
    
        return "Car{" +
                "brand='" + brand + '\'' +
                ", maxSpeed=" + maxSpeed +
                '}';
    }

    public String getBrand() {
    
    
        return brand;
    }

    public void setBrand(String brand) {
    
    
        this.brand = brand;
    }

    public int getMaxSpeed() {
    
    
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
    
    
        this.maxSpeed = maxSpeed;
    }

    public Car(String brand, int maxSpeed) {
    
    
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }
}
public class Person implements Cloneable {
    
    
    private String name;
    private Car car;

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

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", car=" + car +
                '}';
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    public Person(String name, Car car) {
    
    
        this.name = name;
        this.car = car;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Car car = new Car("audi", 150);
        Person person=new Person("ding",car);
        Person person1= (Person) person.clone();
        System.out.println("修改car之前:");
        System.out.println(person);
        System.out.println(person1);
        System.out.println("修改car之后:");
        car.setBrand("benchi");
        car.setMaxSpeed(200);
        System.out.println(person);
        System.out.println(person1);
        System.out.print("使用Object默认的clone方法:");
        System.out.println(person.getCar()==person1.getCar());
    }
}

Resultado de la ejecución:
Inserte la descripción de la imagen aquí
este método de clonación obviamente significa que el Car del objeto original y el objeto clonado son la misma referencia. En otras palabras, el objeto Car no se clona. Si se modifica el valor del objeto Car, cambiarán tanto el objeto original como el objeto clonado. Esto no es lo que queremos ver.

Por lo tanto, necesitamos que incluso el objeto en el objeto sea un objeto nuevo. Cada atributo está completamente copiado, lo cual es un clon profundo.
Para lograr una clonación profunda , necesitamos modificar el método de clonación en Person, y el código de prueba getCar () permanece sin cambios.

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        Person person= (Person) super.clone();
        person.setCar((Car) person.getCar().clone());
        return person;
    }

Probar de nuevo:
Inserte la descripción de la imagen aquí
hacerlo es continuar clonando recursivamente tipos de objetos no básicos sobre la base de super.clone.

Evidentemente, este método es engorroso y poco fiable.

2. Implementar la interfaz de serialización

2.1 Utilice la propia serialización de Java para convertir a números binarios y luego deserializar a objetos

Clase de herramienta de serialización ObjectStream

package com.dl.JavaBase;

import java.io.*;

public class SerialiazableUtil {
    
    

    public SerialiazableUtil() {
    
    
        throw new AssertionError();
    }

    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T deepCloneObject(Object object) throws IOException {
    
    
        T deepClone = null;
        ObjectInputStream ois = null;
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
        )
        {
    
    
            oos.writeObject(object);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos
                    .toByteArray());
            ois = new ObjectInputStream(bais);
            deepClone = (T)ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            if(ois != null){
    
    
                ois.close();
            }
        }
        return deepClone;
    }
}

Categoría de prueba:

package com.dl.JavaBase;

import java.io.IOException;
import java.io.Serializable;

class Car implements Serializable {
    
    
    private static final long serialVersionUID = 4982206063131788088L;
    private String brand;//品牌
    private int maxSpeed;//最高时速

    @Override
    public String toString() {
    
    
        return "Car{" +
                "brand='" + brand + '\'' +
                ", maxSpeed=" + maxSpeed +
                '}';
    }

    public String getBrand() {
    
    
        return brand;
    }

    public void setBrand(String brand) {
    
    
        this.brand = brand;
    }

    public int getMaxSpeed() {
    
    
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
    
    
        this.maxSpeed = maxSpeed;
    }

    public Car(String brand, int maxSpeed) {
    
    
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }
}
public class Person implements Serializable {
    
    

    private static final long serialVersionUID = 6957528274628957691L;
    private String name;
    private Car car;

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", car=" + car +
                '}';
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    public Person(String name, Car car) {
    
    
        this.name = name;
        this.car = car;
    }

    public static void main(String[] args) throws CloneNotSupportedException, IOException {
    
    
        Person person=new Person("ding",new Car("audi",150));
        Person person1= SerialiazableUtil.deepCloneObject(person);
        System.out.print("Java默认序列化方式:");
        System.out.println(person.getCar()==person1.getCar());
    }
}

resultado de la operación:

Inserte la descripción de la imagen aquí
Otra forma es utilizar herramientas de serialización como fastjson para serializar y deserializar objetos para clonar.

2.2 serialización fastjson

Dependencia de Maven

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
</dependency>

Clase de auto:

package com.dl.JavaBase;

import java.io.Serializable;

public class Car implements Serializable {
    
    
    private static final long serialVersionUID = 4982206063131788088L;
    private String brand;//品牌
    private int maxSpeed;//最高时速

    @Override
    public String toString() {
    
    
        return "Car{" +
                "brand='" + brand + '\'' +
                ", maxSpeed=" + maxSpeed +
                '}';
    }

    public String getBrand() {
    
    
        return brand;
    }

    public void setBrand(String brand) {
    
    
        this.brand = brand;
    }

    public int getMaxSpeed() {
    
    
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
    
    
        this.maxSpeed = maxSpeed;
    }

    public Car(String brand, int maxSpeed) {
    
    
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }
}

Clase de persona

package com.dl.JavaBase;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;
public class Person implements Serializable {
    
    

    private static final long serialVersionUID = 6957528274628957691L;
    private String name;
    private Car car;

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", car=" + car +
                '}';
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    public Person(String name, Car car) {
    
    
        this.name = name;
        this.car = car;
    }

    public static void main(String[] args) throws CloneNotSupportedException, IOException {
    
    
        Person person=new Person("ding",new Car("audi",150));
        //Person person1 = JSONObject.parseObject(JSONObject.toJSONString(person), Person.class);
        Person person1 = JSONObject.parseObject(JSONObject.toJSONBytes(person), Person.class);
        System.out.println("fastjson方式:");
        System.out.println(person.getCar()==person1.getCar());
    }
}

resultado de la operación:
Inserte la descripción de la imagen aquí

para resumir:

Hay dos formas principales de implementar la clonación de objetos:
1. Implementar la interfaz Cloneable y reescribir el método clone () para completar la copia superficial del objeto.

  • El método de clonación predeterminado de Object es en realidad una copia simple del campo y, para tipos de datos simples, es una copia del valor;
  • Para tipos complejos de campos, es una copia de la dirección del puntero, y el objeto clonado y el objeto original apuntan a un espacio de direcciones.
  • Entonces, el método de clonación predeterminado es la clonación superficial.
  • Para lograr una clonación profunda, debe implementar la interfaz Cloneable y reescribir el método de clonación para cada clase en la implementación de la clase compleja (los objetos en la clase compleja también deben ser objetos nuevos). Para hacerlo, debe continuar tratando no -los básicos sobre la base de super.clone Los objetos de tipo se clonan de nuevo de forma recursiva.
  • Evidentemente, este método es engorroso y poco fiable.

2. Realice la interfaz de serialización Serializable y realice la clonación a través de la serialización y deserialización del objeto, que puede realizar la clonación profunda real.

  • La clonación basada en la serialización y deserialización no es solo una clonación profunda, sino que, lo que es más importante, a través de la restricción genérica, puede verificar si el objeto que se va a clonar admite la serialización. Esta verificación la realiza el compilador.
  • En lugar de lanzar una excepción en tiempo de ejecución, esta solución de resumen es significativamente mejor que usar el método de clonación de la clase Object para clonar un objeto. Es mejor dejar que el problema se exponga en tiempo de compilación que dejar el problema en tiempo de ejecución.

Supongo que te gusta

Origin blog.csdn.net/dl962454/article/details/114780240
Recomendado
Clasificación