affermazione di
Cameron Skinner sopra che "garantisce Collections.unmodifiableMap che la mappa non sarà modificato" è in realtà solo in parte vero in generale, anche se capita di essere precisi per l'esempio specifico nella questione (solo perché il carattere l'oggetto è immutabile). Spiegherò con un esempio.
Collections.unmodifiableMap fornisce solo la protezione che i riferimenti agli oggetti contenuti nella mappa non possono essere modificati. Lo fa limitando il "put" nella mappa che restituisce. Tuttavia, la mappa incapsulata originale può ancora essere modificata al di fuori della classe, in quanto Collections.unmodifiableMap non esegue alcuna copia del contenuto della mappa.
Nella domanda postata da Paulo, gli oggetti Personaggio contenuti nella mappa sono per fortuna immodificabili. Tuttavia, in generale questo potrebbe non essere vero e l'immodificabilità pubblicizzata da Collections.unmodifiableMap non dovrebbe essere l'unica salvaguardia. Ad esempio, vedi l'esempio qui sotto.
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() + " ]"); }
}
Quando si esegue questo esempio, si vede:
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 ]
I startingLocations mappa è incapsulato e solo restituito sfruttando Collections.unmodifiableMap nel metodo getStartingLocations. Tuttavia, lo schema viene sovvertito ottenendo l'accesso a qualsiasi oggetto e quindi modificandolo, come mostrato in "Prova 2" nel codice sopra. Basti dire che si può solo contare su Collections.unmodifiableMap per dare una mappa veramente non modificabile SE gli oggetti contenuti nella mappa sono di per sé immutabili. Se non lo sono, vorremmo copiare gli oggetti nella mappa o limitare in altro modo l'accesso ai metodi di modifica dell'oggetto, se possibile.
Non ti piace il 'finale' o? –
final non renderà la mappa immutabile, solo il riferimento alla mappa. Puoi ancora chiamare metodi (come 'put') sui riferimenti finali. –
In questo esempio, 'final' è necessario. (A meno che '_typesMap' venga resettato su una mappa diversa più tardi ...) –