【发布时间】:2013-03-21 14:45:20
【问题描述】:
抱歉,我的标题可能具有误导性。
这其实是我最近的一次JAVA面试,面试官问我这个问题:如果我们有一个HashMap类型的参数,我们怎么能保证在accepting方法中,用户没有办法修改这个HashMap(即get()方法)
我在面试的时候说用final,面试官根本不领情,在网上找了半天这个话题还是没有头绪。
专家可以帮忙吗?谢谢
【问题讨论】:
标签: java
抱歉,我的标题可能具有误导性。
这其实是我最近的一次JAVA面试,面试官问我这个问题:如果我们有一个HashMap类型的参数,我们怎么能保证在accepting方法中,用户没有办法修改这个HashMap(即get()方法)
我在面试的时候说用final,面试官根本不领情,在网上找了半天这个话题还是没有头绪。
专家可以帮忙吗?谢谢
【问题讨论】:
标签: java
听起来您可能来自 C++ 背景,其中设置参数const 确实会阻止该方法修改对象。在 Java 中,final 仅阻止分配给该变量;您仍然可以调用修改对象本身的方法。
所以,例如:
void callingMethod() {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(1, 2);
badMethod(map);
// NullPointerException
System.out.println(map.get(1).intValue());
}
void badMethod(final HashMap<Integer, Integer> map) {
map.clear();
}
有几种方法可以防止这种情况:
【讨论】:
使用final 不会阻止调用引用上的方法。它只会使引用本身不可更改。所以你的答案是错误的。
我的建议是使用泛型(仅用于此类采访,而不是在程序中!):
Map<String, String> map = new HashMap< String, String >();
map.put("a", "b"); // OK
Map< ? extends String, ? extends String > mapRO = new HashMap< String, String >();
mapRO.put("a", "b"); // Compile error
String value = mapRO.get("a"); // OK
如您所见,使用? extends ... 隐藏泛型类型可防止调用“写入”方法(如put),因为它们通常需要完全定义类型。但是你仍然可以拨打clear(),所以这是一个非常池安全的概念。
您也可以使用一些包装器,它会在所有“写入”方法调用时引发异常。
【讨论】:
String 类型。因此,您可以采用任何其他类型,可以作为示例进行子类化。
我认为这是不可变或不可修改的地图。
Collections#unmodifiableCollection
它返回指定地图的不可修改视图。这种方法 允许模块为用户提供对内部的“只读”访问 地图。对返回映射的查询操作“通读”到 指定地图,并尝试修改返回的地图,是否直接 或通过其集合视图,导致 UnsupportedOperationException。
【讨论】:
使用Collections.unmodifiableMap包裹您正在传递的地图
【讨论】:
Collections.unmodifiableMap(myMap) 将返回只读映射。您应该处理由此返回的 Map 对象。
【讨论】:
如何从该 Hashmap 中创建一个不可修改的 Collection,例如 here?
然后你会这样做:
yourMethod(Collections.unmodifiableMap(yourHashmap));
仅使用 final 意味着您将无法在此块中用另一个引用覆盖该引用,它不会阻止对该对象的任何方法调用。
【讨论】:
有两种方法
1) this.map = Collections.unmodifiableMap(map);
2) 防御性复制:this.map = new HashMap(map);
【讨论】: