英文:
Find a value of a map with the inverse key
问题
我目前有一个包含以下值的映射:
private static final Map<Entrie, somePOJO> MAP = new ConcurrentHashMap<>();
static {
MAP.put(Object.of(A.class, B.class), new someOtherClass());
}
那个Object类是我创建的一个类,用来模拟键值关系。
我想要做的是,通过搜索相反的键来获取someOtherClass的实例。
例如:
MAP.get(Object.of(B.getClass, A.getCall))
应该返回new someOtherClass的实例,但实际上返回null,这是预期的,因为没有像我搜索的那种键。
有关如何解决这个问题的任何提示吗?
英文:
I currently have a map with the following values:
private static final Map<Entrie, somePOJO> MAP = new ConcurrentHashMap<>();
static {
MAP.put(Object.of(A.class, B.class), new someOtherClass());
}
That Object class is a class that I create to simulate a key, value relation.
What I want to do is to get the instance of the someOtherClass but by searching for the reverse key.
Example:
MAP.get(Object.of(B.getClass, A.getCall)) should return the instance of new someOtherClass, but it returns null as expected because there is no key like the one I was searching.
Any tips on how to workarround the problem?
答案1
得分: 2
考虑将键类型设置为无序。例如,使用哈希集。然后,A>B和B>A的配对将变为相等,将被视为地图的相同键。
MAP.put(Set.of(A.class, B.class), new someOtherClass());
MAP.get(Set.of(B.class, A.class)); // 将返回新的someOtherClass()
英文:
Consider making the key type unordered. E.g. use a hash set. Then the pairs of A>B and B>A become equal, and will be considered as same key for the map.
MAP.put(Set.of(A.class, B.class), new someOtherClass());
MAP.get(Set.of(B.class, A.class)); // will return the new someOtherClass()
答案2
得分: 0
听起来你希望Object.of("A", "B")
和Object.of("B", "A")
都被视为相同的键 - 任何一个键只能与一个对象关联,并且将它们中的任何一个作为map
的get
调用的参数,都会返回与其关联的对象。
你有两个选项:
修复equals和hashCode的实现
地图实现使用特定的“相等函数”来确定是否将键视为相等。
大多数使用equals和hashCode,我会解释一下。另外两个主要的替代方案是TreeMap
,它使用构造函数中提供的比较器来确定(如果你不提供比较器,则键类型必须是Comparable
,并且将使用其compareTo方法)。它完全忽略了equals
和hashCode
。另一个是WeakHashMap
,它使用对象标识,但在这里完全无用。
几乎所有其他的地图实现(比如java.util.HashMap
)都是通过调用键对象的equals
和hashCode
方法来确定相等性的。规则如下:
a.equals(b)
的结果必须与b.equals(a)
相同。a.equals(a)
必须返回true。- 调用
equals
不能抛出任何异常。 - 如果
a.equals(b)
,则a.hashCode()
必须等于b.hashCode()
,但反过来未必成立:如果a.hashCode()
与b.hashCode()
相同,则它们未必是a.equals(b)
,在这种情况下(哈希码相同,但不相等),它们...并不相等。但如果它们相等,它们的哈希码必须相同,否则地图就无法正常工作。是的,return 1;
在hashCode()
的实现中在技术上是合法的。 - 如果哈希码“分布不良”,也就是说,许多不相等的对象具有相同的哈希码,那么地图实现的普通性能特性(即使有数百万条条目,查找也很快)将不再有效(它们会变慢)。
鉴于所有这些,你需要发明一个hashCode()
和equals(Object)
方法的实现,使得Object.of("A", "B")
和Object.of("B", "A")
相等。对于哈希码,你可以对每个单独的值进行哈希并将它们异或在一起,因为异或关系是可交换的:a^b^c
的结果与c^a^b
相同 - 顺序无关紧要。对于相等性,嗯,你是一个程序员,编写一个算法。一种简单快速的方法是将所有元素放入TreeSet
,即将所有元素存储在自排序数据结构中,从而保证具有相同元素的任何版本必然按相同顺序排列,从而使相等性变得简单。
但我不能更改equals和hashCode的实现
那么另一个选择是使用TreeMap
(但请注意,这意味着地图的内容将根据比较器进行排序),使用其中一个接受Comparator<YourObj>
的构造函数。规则变为:
comparator.compare(a, a)
必须返回0
- 比较器必须是一致的:
comparator.compare(a, b)
必须匹配comparator.compare(b, a)
:如果一个返回0,另一个也必须返回0。如果一个返回正数,另一个必须返回负数。 - 除非两个参数中有一个为空,否则不允许出现NPE。
- 如果
comparator.compare(a, b)
为0,则这两个对象被视为相等。
因此,任务就是确保比较Object.of("A", "B")
和Object.of("B", "A")
时返回0。在这种安排中没有hashCode函数,所以你需要做的就是让这种情况发生,但如果它们不相等,你不能随意返回“-1”或“+1”,它必须是一致的。
英文:
It sounds like you want both Object.of("A", "B")
as well as Object.of("B", "A")
to be treated as if they are the exact same key - only one object can be associated with either of these, and using either as argument to map's get
call returns the object you associated with them.
You have two options:
Fix the equals and hashCode implementations
A map implementation uses a certain 'equality function' to determine if keys are considered equal.
Most use equals and hashCode, which I'll get to. The 2 major alternatives are TreeMap
which uses the comparator you provided in the constructor (and if you don't provide one, the Key type must be Comparable
, and its compareTo method will be used). It completely ignores equals
and hashCode
. The other is WeakHashMap
which uses object identity and is completely useless here.
Pretty much everything else (such as java.util.HashMap
) determines equality by invoking the key object's equals
and hashCode
methods. The rules are:
- The result of
a.equals(b)
must be the same asb.equals(a)
a.equals(a)
must return true.- invoking
equals
must not throw any exceptions. - if
a.equals(b)
, thena.hashCode()
must equalb.hashCode()
, but the reverse need not be true: Ifa.hashCode()
is the same asb.hashCode()
, then they need not bea.equals(b)
, and in that case (same hashcode, but not equal), they.. just aren't equal. But if they ARE equal, they must have the same hashcode or map just doesn't work. Yes,return 1;
is a technically legal impl ofhashCode()
- If the hashcodes are 'badly distributed', as in, lots of non-equal objects have the same hashcode, the map impl's ordinary performance characteristics (such as fast lookup even if there are millions of entries) is no longer valid (they become slow).
Given all that, what you need to invent is an impl of hashCode()
and equals(Object)
methods such that Object.of("A", "B")
and Object.of("B", "A")
are equal. For hashcodes, you can hash up every individual value and xor them together, because the xor relation is commutative: a^b^c
is the same result as c^a^b
- order doesn't matter. For equality, well, you're a programmer, program an algorithm. A simple and fast way is to toss all elements into a TreeSet
, i.e. to store all elements in a self-sorting data structure, thus guaranteeing any version of that structure with the same elements necessarily has them in the same order, thus making equality trivial.
I can't mess with the equals and hashCode impl though
Then the other option is to use TreeMap
(but note, this means the map's contents will be sorted according to the comparator), using one of the constructors that takes a Comparator<YourObj>
. The rules then become:
comparator.compare(a, a)
must return0
- The comparator needs to be consistent:
comparator.compare(a, b)
needs to matchcomparator.compare(b, a)
: If one returns 0, the other must too. If one returns a positive number the other must return a negative number. - No NPEs allowed unless one of the two params is null.
- If
comparator.compare(a, b)
is 0, then the 2 objects are considered equal.
So, the job then becomes to ensure that comparing Object.of("A", "B")
and Object.of("B", "A")
returns 0. There's no hashCode function in this arrangement, so all you need to do, is to make that happen, but you can't just arbitrarily return -1
or +1
if they aren't equal, it has to be consistent.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论