Java HashMap键值问题

4

我目前正在制作一个自定义序列化程序,作为项目的一部分。在这里,我需要对引用进行序列化,这意味着如果两个字段在序列化之前引用同一个项目,则在反序列化后也应该如此。

为此,我使用了HashMap,将每个对象映射到一个ID,我可以将其用作每个序列化对象的属性,同时跟踪哪些对象已经被序列化。然而,我遇到了一些问题。

似乎Java HashMap仅在键上检查相等性,而不检查它们是否是相同的引用。例如,在下面的示例中,变量b最终为true:

HashMap<Object, Integer> map = new HashMap<Object, Integer>();
LinkedList<Object> ll1 = new LinkedList<Object>();
LinkedList<Object> ll2 = new LinkedList<Object>();
map.put(ll1, 5);
boolean b = map.containsKey(ll2);

有时结果完全没有意义。在这里,b也是true:

HashMap<Object, Integer> map = new HashMap<Object, Integer>();
LinkedList<Object> ll1 = new LinkedList<Object>();
Stack<Object> stack = new Stack<Object>();
map.put(ll1, 5);
boolean b = map.containsKey(stack);

我希望ContainsKey方法不仅调用equals方法,还要使用“==”运算符检查引用是否相同。我能否在无需查看整个键集的情况下实现这一点?
提前致谢。

我认为你可以使用自己的地图实现。 - kosa
使用空的LinkedList作为HashMap键并不太合理,这让我觉得你试图做的事情在概念上存在其他问题。 “我需要序列化引用”不是很清楚,但这让我想到警报。 如果这确实是您需要的,请使用Boann的答案。 但如果可能的话,我鼓励您重新审视您的序列化器需求。 - dimo414
@dimo414 对我来说是有道理的。如果两个引用指向同一个对象,你不想将其序列化两次,所以你需要跟踪已经处理过的对象。同样地,如果两个对象彼此引用,你需要跟踪它们以防止陷入无限循环。 - Boann
@dimo414 如果我在程序数据序列化中引用了一个列表的两个位置,我需要能够从一个引用更改列表并从第二个引用检索更改后的列表。如果每次反序列化时创建新实例,则无法实现此目标。 - Reppien
对我来说,这就是问题所在。尝试对同一列表进行多次序列化听起来像是可以通过重构要序列化的类来解决的概念问题,并且很可能会避免一些令人困惑的行为。 - dimo414
可能吧,但我不被允许在待序列化的类上做太多更改,因此序列化程序必须支持它们所包含的任何内容 :) - Reppien
1个回答

5

Map接口的通用契约是,如果两个键都为null,则认为它们相等;或者如果它们不为null且a.equals(b),则认为它们相等。除非键类的equals方法实现了这一点,否则它不使用==进行比较。

你的LinkedListStack对象相等的原因是它们都实现了List接口,并且List.equals的定义是,如果两个列表具有相同的大小,并且按相同顺序包含相同的对象,则它们相等。由于它们都为空,所以它们“相等”。

我相信你正在寻找IdentityHashMap。它故意违反了Map接口的契约,仅使用==而不是Object.equals()来比较对象。同样地,对于哈希码,它使用System.identityHashCode而不是任何重写的Object.hashCode()


正是我所需要的。非常感谢! - Reppien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接