Question

I recently discovered that class ProcessBuilder in JDK6 does not override equals(). Is there a reason? Since the class is mutable, I can understand why it does not override hashCode().

I was surprised to see this code not work:

ProcessBuilder x = new ProcessBuilder("abc", "def");
ProcessBuilder y = new ProcessBuilder("abc", "def");
if (x.equals(y)) {  // they are never equal
    // something important here
}

I looked into the JDK6 source code for class ProcessBuilder, and I do not see an override for equals().

I have a feeling there is a deeper reason, beyond this one class. Perhaps this is intentional?

No correct solution

OTHER TIPS

It is considered best practice to make mutable objects not equal unless they are the same object. This is because the object could change later. Consider the following

Set<ProcessBuilder> pbSet = new HashSet<>();
pbSet.add(x);
pbSet.add(y);
// if x and y were equal pbSet would have one element.
y.setSomething()
// should pbSet have one or two elements.

Worse than this is the opposite case where two object could be different but later made the same. This means the Set would have a duplicate object.

What is interesting is that collections are mutable but still have equals and hashCode. I think the reason this is the case is that there is no immutable collections. e.g. String override equals(), StringBuilder does not.

To complement @PeterLawrey's answer: for objects which are mutable by nature, implementing equals and hashcode is risky in any event. You have no guarantee that such objects are safely published at all. It therefore makes sense that the authors of such classes just "gave up" on equals and hashcode for such classes.

HOWEVER: if you are reasonably sure that you can control this equality, there is something for you: Guava's Equivalence. If you can ensure sufficiently controlled access to highly mutable classes, this allows you to define an equals/hashcode strategy for such objects so that you can even use them in, say, a HashSet.

More about this Equivalence: for an "unstable" class X which is mutable by nature, but for which you can guarantee equivalence in a given context, you implement an Equivalence<X>. Then you "wrap" these instances of X into, for instance, a:

Set<Equivalence.Wrapper<X>>

You'll then add to this set using:

set.add(eq.wrap(x));

where eq is your implementation of an Equivalence.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top