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!"; //!!!
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? ¿Significa esto que con cada método getter puedes avanzar para acceder al campo privado? (No quiero ninguna biblioteca como Guava. Solo necesito saber la forma correcta de hacerlo).
final
hace evitar que la modificación del campo . Sin embargo, evitar la modificación de loObject
mencionado por un campo es más complicado.Respuestas:
Debes devolver un copia de su matriz.
fuente
Unmodifiable List
.Si puede usar una Lista en lugar de una matriz, Colecciones proporciona una lista no modificable :
fuente
Collections.unmodifiableList(list)
como asignación al campo, para asegurarse de que la clase no cambie la lista.String
es, pero si son mutables, es posible que deba hacerse algo para evitar que la persona que llama los cambie.El modificador
private
protege solo el campo mismo del acceso desde otras clases, pero no las referencias a objetos de este campo. Si necesita proteger el objeto referenciado, simplemente no lo entregue. Cambioa:
o para
fuente
El
Collections.unmodifiableList
ya ha sido mencionado, ¡Arrays.asList()
curiosamente no! Mi solución también sería usar la lista desde el exterior y envolver la matriz de la siguiente manera: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. Por lo tanto, la copia es un enfoque simple pero realmente malo: yo diría "barato", ¡pero costoso para la memoria! Especialmente cuando tienes más de 2 elementos.
Si nos fijamos en el código fuente de
Arrays.asList
y enCollections.unmodifiableList
realidad no hay mucho creado. El primero simplemente envuelve la matriz sin copiarla, el segundo simplemente envuelve la lista, haciendo que los cambios no estén disponibles.fuente
immutableList
todo el camino!Arrays.asList
yCollections.unmodifiableList
son probablemente más baratas para matrices más grandes. Tal vez alguien pueda calcular cuántos elementos son necesarios, pero ya he visto código en bucles for con matrices que contienen miles de elementos que se copian solo para evitar modificaciones, ¡eso es una locura!También puede usar
ImmutableList
cuál debería ser mejor que el estándarunmodifiableList
. La clase es parte de las bibliotecas de guayaba que fue creada por Google.Aquí está la descripción:
Aquí hay un ejemplo simple de cómo usarlo:
fuente
Test
clase para dejar la lista devuelta sin alterar . Debe asegurarse de queImmutableList
se devuelva y de que los elementos de la lista también sean inmutables. De lo contrario, mi solución también debería ser segura.en este punto de vista, debe usar la copia de la matriz del sistema:
fuente
clone
, y no es tan conciso.Puede devolver una copia de los datos. La persona que llama que elige cambiar los datos solo cambiará la copia
fuente
El meollo del problema es que está devolviendo un puntero a un objeto mutable. Ups O representa el objeto 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 "besar primos".
fuente
Devolver una lista no modificable es una buena idea. Pero una lista que no se puede modificar durante la llamada al método getter puede ser cambiada por la clase o las clases derivadas de la clase.
En su lugar, debe dejar en claro a cualquiera que extienda la clase que la lista no debe modificarse.
Entonces, en su ejemplo, podría conducir al siguiente código:
En el ejemplo anterior, hice
STRINGS
público el campo, 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
private final List<String>
campo que no se puede modificar durante la construcción de la instancia de clase. El uso de argumentos constantes o de instanciación (del constructor) depende del diseño de la clase.fuente
Sí, debe devolver una copia de la matriz:
fuente