declaración de
Cameron Skinner anteriormente que "garantiza Collections.unmodifiableMap que el mapa no será modificado" es en realidad sólo en parte cierto en general, a pesar de que pasa a ser preciso para el ejemplo específico en la cuestión (sólo porque el personaje el objeto es inmutable). Voy a explicar con un ejemplo.
Collections.unmodifiableMap en realidad solo le ofrece protección que las referencias a los objetos que se encuentran en el mapa no se pueden cambiar. Lo hace al restringir el 'put' en el mapa que devuelve. Sin embargo, el mapa encapsulado original aún se puede modificar desde fuera de la clase porque Collections.unmodifiableMap no realiza ninguna copia del contenido del mapa.
En la pregunta publicada por Paulo, los objetos de caracteres que se encuentran en el mapa son afortunadamente no modificables. Sin embargo, en general, esto puede no ser cierto y la no modificabilidad anunciada por Collections.unmodifiableMap no debe ser la única salvaguarda. Por ejemplo, mira el ejemplo a continuación.
import java.awt.Point;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SeeminglyUnmodifiable {
private Map<String, Point> startingLocations = new HashMap<>(3);
public SeeminglyUnmodifiable(){
startingLocations.put("LeftRook", new Point(1, 1));
startingLocations.put("LeftKnight", new Point(1, 2));
startingLocations.put("LeftCamel", new Point(1, 3));
//..more locations..
}
public Map<String, Point> getStartingLocations(){
return Collections.unmodifiableMap(startingLocations);
}
public static void main(String [] args){
SeeminglyUnmodifiable pieceLocations = new SeeminglyUnmodifiable();
Map<String, Point> locations = pieceLocations.getStartingLocations();
Point camelLoc = locations.get("LeftCamel");
System.out.println("The LeftCamel's start is at [ " + camelLoc.getX() + ", " + camelLoc.getY() + " ]");
//Try 1. update elicits Exception
try{
locations.put("LeftCamel", new Point(0,0));
} catch (java.lang.UnsupportedOperationException e){
System.out.println("Try 1 - Could not update the map!");
}
//Try 2. Now let's try changing the contents of the object from the unmodifiable map!
camelLoc.setLocation(0,0);
//Now see whether we were able to update the actual map
Point newCamelLoc = pieceLocations.getStartingLocations().get("LeftCamel");
System.out.println("Try 2 - Map updated! The LeftCamel's start is now at [ " + newCamelLoc.getX() + ", " + newCamelLoc.getY() + " ]"); }
}
Al ejecutar este ejemplo, ver:
The LeftCamel's start is at [ 1.0, 3.0 ]
Try 1 - Could not update the map!
Try 2 - Map updated! The LeftCamel's start is now at [ 0.0, 0.0 ]
Los startingLocations mapa se encapsula y sólo regresó al aprovechar Collections.unmodifiableMap en el método getStartingLocations. Sin embargo, el esquema se subvierte al obtener acceso a cualquier objeto y luego cambiarlo, como se ve en "Probar 2" en el código anterior. Basta con decir que solo se puede confiar en Collections.unmodifiableMap para proporcionar un mapa verdaderamente no modificable SI los objetos que se encuentran en el mapa son inmutables. Si no es así, querríamos copiar los objetos en el mapa o restringir el acceso a los métodos modificadores del objeto, si es posible.
¿No te gusta 'final' tampoco? –
final no hará que el mapa sea inmutable, solo la referencia al mapa. Todavía puede llamar a métodos (como 'poner') en las referencias finales. –
En este ejemplo, 'final' es necesario. (A menos que '_typesMap' se restablezca a un mapa diferente más adelante ...) –