I was using a PriorityQueue, and I overrode the equals in MyClass,
PriorityQueue<MyClass> pq = ...
I wanted to make some foreign objects equals to MyClass,
if (pq.contains(foreignObj)) {
...
}
When I looked into the implementation of PriorityQueue, it called this way,
o.equals(queue[i])
Where 'o' was the foreignObj and 'queue[i]' was an instance of MyClass. That caused a major problem, because I expected it called MyClass's equals because I own that so I could make any types of objects 'equals' to mine. And, I don't own the foreign class's source code and could not change anything over there.
Why it didn't code as below, so it'd call my equals instead of someone else's that I don't have control of?
queue[i].equals(o)
CodePudding user response:
Callers can expect a.equals(b)
and b.equals(a)
to have the same result no matter what a
and b
are, as long as they're non-null. It is guaranteed by the contract of the equals
method.
Your implementation is not legal because it isn't symmetric. Per the API documentation:
The equals method implements an equivalence relation on non-null object references:
- It is reflexive: for any non-null reference value
x
,x.equals(x)
should returntrue
.- It is symmetric: for any non-null reference values
x
andy
,x.equals(y)
should returntrue
if and only ify.equals(x)
returnstrue
.- It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.
CodePudding user response:
The code is written to give you the maximum amount of control. When you call contains
, you choose what object you pass as an argument, and the Java queue implementation calls (virtually) the equals
method on that object. If you don't like how foreignObj.equals
is implemented, then wrap foreignObj
in a minimal class that contains it and that overrides equals
to do whatever you want.
public class MyObject {
private ForeignObject foreignObj;
public MyObject(ForeignObject foreignObj) {
this.foreignObj = foreignObj;
}
@Override
public boolean equals(Object that) {
// ... Whatever you want ...
}
}
CodePudding user response:
The idea for Java containers are that you expect all objects in the container to be of the same type (or if they have different types, that instances of different types will never be equal), so it doesn't really matter on which direction you call equals()
(as it is supposed to be insensitive to the order of arguments).
What you are trying to do goes against this basic assumption. If you are doing weird things, you might as well make it weirder and use a wrapper class that just reverses the order of equals()
and use that to wrap your foreign object:
class UndirectEq {
private Object v;
public UndirectEq(Object val) { v = val; }
boolean equals(Object o) { return o.equals(v); }
}
...
if (pq.contains(new UndirectEq(foreignObj))) { ...