【发布时间】:2018-07-30 14:25:43
【问题描述】:
我使用派生自 TreeMap 的类和我自己的比较器作为 LinkedHashMap 中的键。使用此构造时,我发现了一些我无法解释的奇怪行为。也许你们中的一个可以提供帮助。我试图用原语重现我的问题。当我创建原始类型的 TreeMap 时,自然排序顺序就足够了,并且不需要 TreeMap 的构造函数中的比较器,对吧?!
这是 MWE:
package treemapputtest;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapPutTest {
public static void main(String[] args) {
System.out.println("simple:");
simpleTest();
System.out.println("\n\ncomplex:");
complexTest();
}
private static void simpleTest(){
TreeMap<Integer,String> map = new TreeMap<>();
System.out.println("map: " + map.hashCode() + " | " + Integer.toHexString(map.hashCode()));
map.put(1, "a");
System.out.println("map: " + map.hashCode() + " | " + Integer.toHexString(map.hashCode()));
map.put(2, "b");
System.out.println("map: " + map.hashCode() + " | " + Integer.toHexString(map.hashCode()));
}
private static void complexTest(){
TreeMap<Integer,String> internalMap = new TreeMap<>();
internalMap.put(1, "a");
internalMap.put(2, "b");
System.out.println("prior: " + internalMap.hashCode() + " | " + Integer.toHexString(internalMap.hashCode()));
LinkedHashMap<TreeMap<Integer,String>,Double> myMap = new LinkedHashMap<>();
myMap.put(internalMap, 1.0);
doSomethingWithMyInternalMap(myMap.keySet().iterator().next());
System.out.println("after:");
for (Map.Entry<TreeMap<Integer,String>,Double> entry : myMap.entrySet()){
System.out.println(" " + Integer.toHexString(entry.getKey().hashCode()));
}
}
private static void doSomethingWithMyInternalMap(TreeMap<Integer,String> intern){
intern.put(3, "c");
}
}
输出是:
simple:
map: 0 | 0
map: 96 | 60
map: 192 | c0
complex:
prior: 192 | c0
after:
120
所以我的问题是:为什么当我向 TreeMap 添加内容时hashCode() 的结果会发生变化?仅对 TreeMap 而言,这没什么大不了的,但由于这会创建一个“新对象”/对旧对象的引用已更改,因此在更新 LinkedHashMap 中的 TreeMap 后会出现错误。
Object API 表示 hashCode():
hashCode 的一般约定是:每当在 Java 应用程序执行期间对同一个对象多次调用它时,hashCode 方法必须始终返回相同的整数,前提是对象上的 equals 比较中没有使用任何信息修改。
在 TreeMap 中添加额外的东西会改变 TreeMap 的 equals() 方法吗?我是否必须以某种方式覆盖equals() 和hashCode()?
【问题讨论】:
标签: java equals comparator hashcode treemap