Приведенное выше утверждение Кэмерона Скиннера о том, что "Collections.unmodifiableMap гарантирует, что карта не будет изменена", на самом деле только частично в целом верно, хотя оно оказывается точным для конкретного примера в вопросе (только потому что объект Character является неизменным). Я объясню на примере.
Collections.unmodifiableMap фактически защищает вас только от того, что ссылки на объекты, хранящиеся на карте, не могут быть изменены. Он делает это, ограничивая «положить» на карту, которую он возвращает. Однако исходная инкапсулированная карта все еще может быть изменена извне класса, потому что Collections.unmodifiableMap не делает никаких копий содержимого карты.
В вопросе, заданном Пауло, объекты персонажей, хранящиеся на карте, к счастью, не могут быть изменены. Тем не менее, в целом это может быть не так, и немодифицируемость, объявленная Collections.unmodifiableMap, не должна быть единственной защитой. Например, см. Пример ниже.
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() + " ]"); }
}
Когда вы запустите этот пример, вы увидите:
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 ]
Карта initialLocations инкапсулируется и возвращается только путем использования Collections.unmodifiableMap в методе getStartingLocations. Тем не менее, схема подрывается, получая доступ к любому объекту, а затем изменяя его, как показано в «Попытка 2» в приведенном выше коде. Достаточно сказать, что можно полагаться только на Collections.unmodifiableMap, чтобы получить действительно неизменяемую карту, если объекты, содержащиеся на карте, сами являются неизменными. Если это не так, мы бы хотели скопировать объекты на карте или иным образом ограничить доступ к методам модификатора объекта, если это возможно.