将Collections.unmodifiableMap与ConcurrentHashMap / HashMap用作参数

时间:2019-01-26 00:12:34

标签: java hashmap concurrenthashmap

我从Goetz的书(Java Concurrency in Practice)中获得了以下代码。

这本书说将ConcurrentMap作为Collections.unmodifiableMap中的参数传递,将给出位置的“实时”视图(即,调用下面的getLocations()),这意味着对setLocation的调用将反映给调用者。

但是,将HashMap作为Collections.unmodifiableMap中的参数传递将给出位置的原始视图(静态视图)(即,在下面调用getLocationsAsStatic())

有人会解释背后的原因吗?谢谢

@ThreadSafe
public class DelegatingVehicleTracker {
    private final ConcurrentMap<String, Point> locations;
    private final Map<String, Point> unmodifiableMap;

    public DelegatingVehicleTracker(Map<String, Point> points) {
        locations = new ConcurrentHashMap<String, Point>(points);
        unmodifiableMap = Collections.unmodifiableMap(locations);
    }

    public Map<String, Point> getLocations() {
        return unmodifiableMap;
    }

    public Point getLocation(String id) {
        return locations.get(id);
    }

    public void setLocation(String id, int x, int y) {
        if (locations.replace(id, new Point(x, y)) == null)
            throw new IllegalArgumentException("invalid vehicle name: " + id);
    }

    // Alternate version of getLocations (Listing 4.8)
    public Map<String, Point> getLocationsAsStatic() {
        return Collections.unmodifiableMap(
                new HashMap<String, Point>(locations));
    }
}

@Immutable
public class Point {
    public final int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

1 个答案:

答案 0 :(得分:1)

行为上的差异不是由于地图的类型不同,而是地图的创建方式。 Collections.unmodifiableMap只会包装给定的地图。

您的ConcurrentMap<String, Point> locations是您要修改的地图,因此,在包装它时,使用不可修改的地图时,您仍然会看到最新的值。

不过,您的HashMap是使用new HashMap<String, Point>(locations)创建的。 this constructor的文档说:

  

使用与指定Map相同的映射构造一个新的HashMap。

     

参数:
  m-要在其地图中放置其映射的地图

因此它实际上将给定映射的所有条目复制到新创建的映射中。因此,此新地图与locations地图不再相关。