卡梅隆·斯金纳(Cameron Skinner)上面关于“Collections.unmodifiableMap保证地图不会被修改”的陈述实际上只是部分正确,尽管它恰好对于问题中的特定示例是准确的(只是因为Character对象是不可变的)。我将用一个例子来解释。
Collections.unmodifiableMap 实际上只为您提供了保护,即对映射中保存的对象的引用无法更改。它通过限制返回的地图中的“put”来做到这一点。但是,原始封装的映射仍然可以从类外部进行修改,因为 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 ]
startingLocations 映射是封装的,并且只能通过利用 getStartingLocations 方法中的 Collections.unmodifiableMap 返回。但是,通过访问任何对象然后更改它来破坏该方案,如上面代码中的“Try 2”所示。可以说,如果地图中保存的对象本身是不可变的,那么只能依靠 Collections.unmodifiableMap 来给出一个真正不可修改的地图。如果不是,我们希望复制映射中的对象,或者以其他方式限制对对象的修饰符方法的访问(如果可能)。