¿Cómo implementar una clase inmutable como String en Java?

Si preguntas cuál es la clase de Java que más usas en el desarrollo diario, Ah Fen apostará a que definitivamente es String.class. Hablando de String, todo el mundo sabe que String es una clase inmutable, aunque se usa mucho, ¿alguna vez has pensado en cómo crear tu propia clase inmutable? En este artículo, Ah Fen te llevará a practicar y crear tu propia clase inmutable.

Características
Antes de escribir código manualmente, primero comprendamos qué características tienen las clases inmutables.

Al definir una clase, debe usar la palabra clave final para la modificación: la razón para usar final para la modificación es que puede evitar ser heredada por otras clases.Una vez que haya herencia de subclase, destruirá el mecanismo de inmutabilidad de la clase principal; las variables miembro deben usar la
modificación final de la palabra clave y deben ser privadas: evitar que los atributos se modifiquen externamente; las
variables miembro no pueden proporcionar métodos setter, solo métodos getter: evitar la modificación externa y evitar devolver las propias variables miembro;
proporcionar constructores para todos campos; saber
en la práctica

Aquí definimos una clase Teacher para probarla, de acuerdo con los puntos que mencionamos anteriormente, agregamos el código final a las definiciones de clase y propiedad como se muestra a continuación.

package com.example.demo.immutable;

import java.util.List;
import java.util.Map;

public final class Teacher {
    
    
  private final String name;
  private final List<String> students;
  private final Address address;
  private final Map<String, String> metadata;

  public Teacher(String name, List<String> students, Address address, Map<String, String> metadata) {
    
    
    this.name = name;
    this.students = students;
    this.address = address;
    this.metadata = metadata;
  }

  public String getName() {
    
    
    return name;
  }


  public List<String> getStudents() {
    
    
    return students;
  }

  public Address getAddress() {
    
    
    return address;
  }

  public Map<String, String> getMetadata() {
    
    
    return metadata;
  }
}
package com.example.demo.immutable;

public class Address {
    
    
  private String country;
  private String city;

  public String getCountry() {
    
    
    return country;
  }

  public void setCountry(String country) {
    
    
    this.country = country;
  }

  public String getCity() {
    
    
    return city;
  }

  public void setCity(String city) {
    
    
    this.city = city;
  }
}

Pensemos si el código anterior es realmente inmutable. Bien, pensemos durante tres segundos y contemos hasta tres en silencio. Para responder a esta pregunta, veamos el siguiente código de prueba.

El resultado de la operación se muestra en la captura de pantalla a continuación. A través de las pruebas, podemos encontrar que simplemente agregar la palabra clave final no puede resolver la inmutabilidad. Nuestra instancia de maestro actual ha sido modificada por la capa externa para eliminar las variables miembro.

Para resolver este problema, también necesitamos modificar nuestra clase Teacher. Lo primero que podemos pensar es que las dos variables miembro de los estudiantes y los metadatos no se pueden devolver directamente a la capa externa, de lo contrario, la modificación de la capa externa afectan directamente nuestra incapacidad para cambiar la clase, entonces podemos modificar el método getter, copiar la variable miembro y devolverla en lugar de devolverla directamente, modificar el código de la siguiente manera

  public List<String> getStudents() {
    
    
    return new ArrayList<>(students);
    //return students;
  }
    public Map<String, String> getMetadata() {
    
    
    return new HashMap<>(metadata);
  //return metadata;
  }

Ejecutamos de nuevo el código de prueba anterior y podemos ver que los datos devueltos son los siguientes: esta vez, la capa externa no ha modificado a nuestros alumnos ni a las variables miembro de metadatos. Pero todavía hay un problema con nuestra variable miembro de dirección, no importa, sigamos adelante.
inserte la descripción de la imagen aquí

Naturalmente, para resolver el problema de la dirección, pensamos en hacer una copia y devolver un objeto de copia al llamar al método getter en lugar de devolver directamente la variable miembro. Luego necesitamos transformar la clase Address y convertirla en Cloneable.Implementamos la interfaz y luego anulamos un método de clonación.El código es el siguiente

package com.example.demo.immutable;

public class Address implements Cloneable{
    
    
  ...// 省略
  @Override
  public Address clone() {
    
    
    try {
    
    
      return (Address) super.clone();
    } catch (CloneNotSupportedException e) {
    
    
      throw new AssertionError();
    }
  }
}

Luego modifique el método getAddress de Teacher

  public Address getAddress() {
    
    
  //return address;
    return address.clone();
  }

A continuación, ejecutemos el código de prueba nuevamente, el resultado es el siguiente, podemos ver que las variables miembro de nuestra instancia de profesor no se han modificado esta vez, ¡hasta ahora hemos completado la creación de un objeto inmutable!
inserte la descripción de la imagen aquí

En la implementación de String,
vimos el funcionamiento de implementación personalizada de clases inmutables. A continuación, observamos brevemente cómo la clase String es inmutable. A través del código fuente, podemos ver que String también usa la palabra clave final para evitar ser heredado. por subclases. , y las variables miembro correspondientes que almacenan valores específicos también usan la palabra clave final.
inserte la descripción de la imagen aquí

Y la subcadena de método proporcionada externamente también es un nuevo objeto String proporcionado externamente en forma de copia.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Enlace original: https://mp.weixin.qq.com/s/fOXeblVcw9Ph5ug5eehb-A

Supongo que te gusta

Origin blog.csdn.net/weixin_44834205/article/details/128069520
Recomendado
Clasificación