util sort copyof clase array java arrays oop class

java - sort - ¿Cómo evito la modificación de un campo privado en una clase?



documentation array java (10)

Debe devolver una copia de su matriz.

public String[] getArr() { return arr == null ? null : Arrays.copyOf(arr, arr.length); }

Imagina que tengo esta clase:

public class Test { private String[] arr = new String[]{"1","2"}; public String[] getArr() { return arr; } }

Ahora, tengo otra clase que usa la clase anterior:

Test test = new Test(); test.getArr()[0] ="some value!"; //!!!

Así que este es el problema: ¡he accedido a un campo privado de una clase desde afuera! ¿Cómo puedo prevenir esto? Quiero decir, ¿cómo puedo hacer que esta matriz sea inmutable? ¿Esto significa que con cada método getter puede subir de nivel para acceder al campo privado? (No quiero bibliotecas como Guava. Solo necesito saber la forma correcta de hacerlo).


Devolver una lista no modificable es una buena idea. Pero una lista que se hace inmodificable durante la llamada al método getter puede ser cambiada por la clase o las clases que se derivan de la clase.

En su lugar, debe dejar en claro a cualquiera que extienda la clase que la lista no se debe modificar.

Por lo tanto, en su ejemplo, podría generar el siguiente código:

import java.util.Arrays; import java.util.Collections; import java.util.List; public class Test { public static final List<String> STRINGS = Collections.unmodifiableList( Arrays.asList("1", "2")); public final List<String> getStrings() { return STRINGS; } }

En el ejemplo anterior hice público el campo STRINGS , en principio podría eliminar la llamada al método, ya que los valores ya se conocen.

También puede asignar las cadenas a un campo de private final List<String> no modificable durante la construcción de la instancia de clase. El uso de una constante o argumentos de instanciación (del constructor) depende del diseño de la clase.

import java.util.Arrays; import java.util.Collections; import java.util.List; public class Test { private final List<String> strings; public Test(final String ... strings) { this.strings = Collections.unmodifiableList(Arrays .asList(strings)); } public final List<String> getStrings() { return strings; } }


La clave del problema es que está devolviendo un puntero a un objeto mutable. Oops. O bien hace que el objeto sea inmutable (la solución de lista no modificable) o devuelve una copia del objeto.

Como cuestión general, la finalidad de los objetos no protege a los objetos de ser cambiados si son mutables. Estos dos problemas son "primos besos".


Modificador private protege solo el campo en sí del acceso a otras clases, pero no las referencias de objeto por este campo. Si necesita proteger el objeto al que se hace referencia, simplemente no lo divulgue. Cambio

public String [] getArr () { return arr; }

a:

public String [] getArr () { return arr.clone (); }

o para

public int getArrLength () { return arr.length; } public String getArrElementAt (int index) { return arr [index]; }


Puede devolver una copia de los datos. La persona que llama que elige cambiar los datos solo cambiará la copia

public class Test { private static String[] arr = new String[] { "1", "2" }; public String[] getArr() { String[] b = new String[arr.length]; System.arraycopy(arr, 0, b, 0, arr.length); return b; } }


Sí, debes devolver una copia de la matriz:

public String[] getArr() { return Arrays.copyOf(arr); }



También puede usar ImmutableList que debería ser mejor que la lista unmodifiableList estándar. La clase es parte de las bibliotecas de Guava creadas por Google.

Aquí está la descripción:

A diferencia de Collections.unmodifiableList (java.util.List), que es una vista de una colección separada que aún puede cambiar, una instancia de ImmutableList contiene sus propios datos privados y nunca cambiará

Aquí hay un ejemplo simple de cómo usarlo:

public class Test { private String[] arr = new String[]{"1","2"}; public ImmutableList<String> getArr() { return ImmutableList.copyOf(arr); } }


The Collections.unmodifiableList ya se ha mencionado, el Arrays.asList() extrañamente no! Mi solución también sería usar la lista desde el exterior y envolver la matriz de la siguiente manera:

String[] arr = new String[]{"1", "2"}; public List<String> getList() { return Collections.unmodifiableList(Arrays.asList(arr)); }

El problema con la copia de la matriz es: si lo hace cada vez que accede al código y la matriz es grande, seguramente creará mucho trabajo para el recolector de basura. Entonces, la copia es un enfoque simple pero realmente malo, yo diría "barato", ¡pero caro para la memoria! Especialmente cuando tienes más de solo 2 elementos.

Si Arrays.asList el código fuente de Arrays.asList y Collections.unmodifiableList realidad no se crea mucho. La primera simplemente envuelve la matriz sin copiarla, la segunda simplemente ajusta la lista, haciendo que los cambios no estén disponibles.


en este punto de vista, debe usar la copia de matriz del sistema:

public String[] getArr() { if (arr != null) { String[] arrcpy = new String[arr.length]; System.arraycopy(arr, 0, arrcpy, 0, arr.length); return arrcpy; } else return null; } }