Java树映射:不同的对象在“之后”;把“放”进去;?
我使用一个从TreeMap派生的类和我自己的比较器作为LinkedHashMap中的键。使用这种结构,我发现了一些我无法解释的奇怪行为。也许你们中的一个能帮上忙。我试图用原语重现我的问题。当我创建一个基元类型的树映射时,自然排序应该足够了,并且不需要在树映射的构造函数中使用比较器,对吧 以下是MWE:Java树映射:不同的对象在“之后”;把“放”进去;?,java,equals,comparator,hashcode,treemap,Java,Equals,Comparator,Hashcode,Treemap,我使用一个从TreeMap派生的类和我自己的比较器作为LinkedHashMap中的键。使用这种结构,我发现了一些我无法解释的奇怪行为。也许你们中的一个能帮上忙。我试图用原语重现我的问题。当我创建一个基元类型的树映射时,自然排序应该足够了,并且不需要在树映射的构造函数中使用比较器,对吧 以下是MWE: package treemapputtest; import java.util.LinkedHashMap; import java.util.Map; import java.util.Tr
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");
}
}
所以我的问题是:hashCode()?仅对于树映射而言,这并不是什么大问题,但由于这会创建一个“新对象”/对旧对象的引用被更改,因此在LinkedHashMap中更新树映射后会出现错误
hashCode()的值为:
hashCode的一般约定是:在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode时,hashCode方法必须一致地返回相同的整数,前提是不修改对象上的equals比较中使用的信息
在TreeMap中添加额外的内容会改变TreeMap的equals()方法吗?我是否必须以某种方式重写equals()
和hashCode()
?我想你对这里的hashCode
有误解。让我们强调你在这里引用的文本中的要点:
hashCode的一般约定是:在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode时,hashCode方法必须一致地返回相同的整数,,前提是不修改对象的equals比较中使用的信息
无论何时在地图中添加(或删除)数据,都是在更改其equals
方法中使用的信息-空地图不等于包含[1->a]
的地图,包含[1->a]
的地图不等于包含[1->a;2->b]
的地图
这与创建新对象无关,对旧贴图的引用不会改变。如果调用而不是,则无论调用多少次put
,对象引用都不会更改。我认为您对这里的hashCode
有误解。让我们强调你在这里引用的文本中的要点:
hashCode的一般约定是:在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode时,hashCode方法必须一致地返回相同的整数,,前提是不修改对象的equals比较中使用的信息
无论何时在地图中添加(或删除)数据,都是在更改其equals
方法中使用的信息-空地图不等于包含[1->a]
的地图,包含[1->a]
的地图不等于包含[1->a;2->b]
的地图
这与创建新对象无关,对旧贴图的引用不会改变。如果调用而不是,则无论调用多少次put
,对象引用都不会更改
在TreeMap中添加额外的内容会改变TreeMap的equals()方法吗
是的,当然,因为对于地图来说
将指定对象与此映射进行相等性比较。如果给定对象也是一个映射并且两个映射表示相同的映射,则返回true。更正式地说,如果m1.entrySet()等于(m2.entrySet()),则两个映射m1和m2表示相同的映射
因此,映射的每个条目都用于检查相等性,因此也用于计算哈希代码。并添加一个条目,从而修改哈希代码
您希望hashCode是对象的某种不可变标识符。不是。一点也不
在TreeMap中添加额外的内容会改变TreeMap的equals()方法吗
是的,当然,因为对于地图来说
将指定对象与此映射进行相等性比较。如果给定对象也是一个映射并且两个映射表示相同的映射,则返回true。更正式地说,如果m1.entrySet()等于(m2.entrySet()),则两个映射m1和m2表示相同的映射
因此,映射的每个条目都用于检查相等性,因此也用于计算哈希代码。并添加一个条目,从而修改哈希代码
您希望hashCode是对象的某种不可变标识符。不是。一点也不
在TreeMap中添加额外的内容会改变TreeMap的equals()方法吗?我是否必须以某种方式重写equals()和hashCode()
为什么不呢?新的TreeMap
为空。因此,根据您的推理,如果它的equals()
和hashCode()
方法没有根据TreeMap
的内容进行调整,那么TreeMap
的所有实例(从空开始)都将具有相同的hashCode,因为它将是在创建时计算的相同实例,其中没有任何条目,不管后面添加了什么
大多数集合的equals()
和hashCode()
函数根据其内容进行调整。这样,可以将元素的集
或列表
与元素的集
或列表
的另一个实例进行比较,如果它们包含相同的元素(在列表
的情况下,顺序相同),则equals()
将返回true。类似地,对于Map
而言,内部equals()
实现确保检查该Map
实现被视为等效的内容
在TreeMap中添加额外的内容会改变TreeMap的equals()方法吗?我是否必须以某种方式重写equals()和hashCode()
为什么不呢?一个新的TreeMap
是em
simple:
map: 0 | 0
map: 96 | 60
map: 192 | c0
complex:
prior: 192 | c0
after:
120