Java Forum / General / July 2005
Comparator.equals()
HK - 27 Jul 2005 10:08 GMT Does anyone have an idea why the interface java.util.Comparator explicitly mentions the equals() method which is anyway defined for each Object?
The docs say: Note that it is always safe not to override Object.equals(Object). However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct Comparators impose the same order.
Well, but why would I generate a large number of Comparators which do exactly the same? My typical comparator looks rather like
public static final Comparator cmpBlaOnBlifield = new Comparator() { // run comparison of Bla objects based on field bli }
Harald.
Chris Uppal - 27 Jul 2005 11:18 GMT > Does anyone have an idea why the interface > java.util.Comparator explicitly mentions the > equals() method which is anyway defined for > each Object? Somewhat tenuous, but possibly it's intended to allow (or encourage) designs where it is possible for code to determine whether a given collection is already sorted in the order that it wants, and thus avoid the expense of resorting needlessly.
-- chris
googmeister@gmail.com - 27 Jul 2005 11:45 GMT > > Does anyone have an idea why the interface > > java.util.Comparator explicitly mentions the [quoted text clipped - 5 lines] > already sorted in the order that it wants, and thus avoid the expense of > resorting needlessly. Sounds reasonable.
But why put equals() in the Comparator interface? It's redundant since every Object already promises to have an equals() method. The Comparable interface doesn't include an equals() method even though the Javadocs recommend you define one that is consistent with compareTo. I don't see this as a big issue, but just wondering if there's a good rule for when to include a redundant method in an interface.
Ingo R. Homann - 27 Jul 2005 12:32 GMT Hi,
> But why put equals() in the Comparator interface? It's redundant > since every Object already promises to have an equals() method. [quoted text clipped - 3 lines] > just wondering if there's a good rule for when to include a > redundant method in an interface. I guess this is only done to indicate that it might be a good idea to really implement this method. It is redundant, you're right.
Ciao, Ingo
Chris Uppal - 27 Jul 2005 13:07 GMT > But why put equals() in the Comparator interface? It's redundant > since every Object already promises to have an equals() method. At a guess: because that's the only way they could get the comment to appear in the JavaDoc.
More serious point: one way of thinking of interfaces is that they are primarily a documentary feature (the fact that the compiler -- or more accurately the type-checker -- understands them can be seen as a machine-assisted special-case of their more general documentary role). As such, if an interface qualifies or extends the contract required/expected by users of objects implementing it, then that fact should appear in the interface specification. Since interfaces mostly only "document" methods, it seems natural to duplicate a method from a parent interface (or from java.lang.Object) in the interface, if that interfaces modifies the more general contract for the method -- even if that extension isn't something that can be expressed in Java except as a comment.
interface Sane { /** * Blah blah blah... */ String getName(); }
interface Insane extends Sane { /** * Returns null on Thursdays. */ String getName(); }
(But I should say that I'm not convinced that Comparator.equals() is a good example of this kind of reasoning -- I would have put that kind of "design note" into the class comment, if anywhere.)
-- chris
Ingo R. Homann - 27 Jul 2005 13:44 GMT Hi,
> (But I should say that I'm not convinced that Comparator.equals() is a good > example of this kind of reasoning -- I would have put that kind of "design > note" into the class comment, if anywhere.) By the way: Can anyone imagine a consistent implementation of Comparator#equals except the inherited one from java.lang.Object?
I mean, (without doing some *really* difficult bytecode-analysis) it should be *impossible* to detect if another Comparator does exactly the same as the Comparator I have implemented. Or am I wrong?
Ciao, Ingo
Thomas Hawtin - 27 Jul 2005 14:07 GMT > By the way: Can anyone imagine a consistent implementation of > Comparator#equals except the inherited one from java.lang.Object? > > I mean, (without doing some *really* difficult bytecode-analysis) it > should be *impossible* to detect if another Comparator does exactly the > same as the Comparator I have implemented. Or am I wrong? As the docs say is is always safe not to override it. All you need to promise is that two Comparators that order differently are not equal. The reverse implication is not specified.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Ingo R. Homann - 27 Jul 2005 14:26 GMT Hi Thomas,
>> By the way: Can anyone imagine a consistent implementation of >> Comparator#equals except the inherited one from java.lang.Object? [quoted text clipped - 6 lines] > promise is that two Comparators that order differently are not equal. > The reverse implication is not specified. I know, but that does not answer my question: Of course, it is OK to override equals so that it always returns false (like e.g. it is OK to override hashCode so that it always returns 0), but what would a *better* implementation look like?
Ciao, Ingo
Thomas Hawtin - 27 Jul 2005 14:37 GMT > I know, but that does not answer my question: Of course, it is OK to > override equals so that it always returns false (like e.g. it is OK to Not always false. a.equals(a) must always be true (for a != null).
> override hashCode so that it always returns 0), but what would a > *better* implementation look like? final public MyComparator implements java.util.Comparator<Tea> { private int someState; ... public int compare(Tea o1, Tea o2) { ... } @Override public int hashCode() { retuen someState; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof MyComparator)) { return false; } MyComparator other = (MyComparator)obj; return this.someState = other.someState; }
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Patricia Shanahan - 27 Jul 2005 15:00 GMT > Hi, > [quoted text clipped - 13 lines] > Ciao, > Ingo Suppose I have a class that represents a row of a database or table. Each column is of a Comparable type. There is Comparator-implementing class, RowComparator, whose constructor takes as parameter a list of column headings to use as sort keys. A RowComparator compares rows using the columns in order of appearance in the list.
Two instances of RowComparator are equal, in the sense specified in the Comparator interface, if, and only if, their column heading lists are equal:
public final class RowComparator implements Comparator{ ... List sortKeys; ... public boolean equals(Object other){ if(!(other instanceof RowComparator){ return false; } return sortKeys.equals(((RowComparator)other).sortKeys); } ... }
The Table could cache sort results, indexed by RowComparator, and return as sort result the result of a previous sort using an equal RowComparator.
Patricia
HK - 27 Jul 2005 15:09 GMT > Suppose I have a class that represents a row of a database or table. > Each column is of a Comparable type. There is Comparator-implementing > class, RowComparator, whose constructor takes as parameter a list of > column headings to use as sort keys. A RowComparator compares rows using > the columns in order of appearance in the list. Good example.
> The Table could cache sort results, indexed by RowComparator, and return > as sort result the result of a previous sort using an equal RowComparator. I would probably have made sure not to generate equal RowComparator instances in the first place by caching the request rather than the resulting Comparator. But I agree that this may often be cumbersome or even impossible.
Thanks, Harald.
Ingo R. Homann - 27 Jul 2005 16:30 GMT Hi,
>>Suppose I have a class that represents a row of a database or table. >>Each column is of a Comparable type. There is Comparator-implementing [quoted text clipped - 9 lines] > I would probably have made sure not to generate equal RowComparator > instances in the first... That is exactly what I meant. Wouldn't it be useful to implement a static method MyComparator.getInstance(param) that always returns the same Comparator-instance for the same param?
And when another Comparator (another implementation) is instantiated, which by coincidence does (semantically) the same, I will always be unable to recoginze, that it does the same!
Ciao, Ingo
Patricia Shanahan - 27 Jul 2005 18:18 GMT > Hi, > [quoted text clipped - 23 lines] > Ciao, > Ingo That is one option, but it is not the only option. Generally, there are two ways to handle logical equality between objects:
1. Override equals and hashCode so that logically equal objects are recognized as being equal.
2. Manipulate object construction so that at most one instance exists for any given logical value, and use object identity as a surrogate for logical equality.
Both seem valid to me. One puts the work of recognizing logical equality in the equals and hashCode methods, the other puts it in the construction. The first is much more direct - you can find out how equals will behave by reading its documentation, without having to look into how objects are constructed.
In both cases, you need to give some thought to subclasses (I ducked the issue in my example by making the class final).
Patricia
Patricia Shanahan - 27 Jul 2005 18:32 GMT >> Hi, >> [quoted text clipped - 46 lines] > > Patricia There is one situation in which it is a lot less work, or even essential, to use the .equals approach. Suppose when the class was designed there was no interest in logical equality, and it was designed with a simple constructor. Later, you decide you need logical equality.
Using the first approach, the changes are localized to the RowComparator class. Using the second approach, each constructor call has to be changed to the corresponding static factory method call.
Patricia
Patricia Shanahan - 27 Jul 2005 14:48 GMT >>>Does anyone have an idea why the interface >>>java.util.Comparator explicitly mentions the [quoted text clipped - 15 lines] > just wondering if there's a good rule for when to include a > redundant method in an interface. Putting an Object method in an interface declaration allows Javadoc declaration of the meaning equals is required to have in classes that implement the interface.
For another example, see the List interface. A List-implementing class should not use the Object equals, because it does not conform to the List contract for equals.
The rule I follow, that seems to be the one used in the API, is to put an object method in an interface declaration if, and only if, there is a different contract from the immediate superinterface or Object.
Patricia
Dale King - 28 Jul 2005 04:48 GMT > Does anyone have an idea why the interface > java.util.Comparator explicitly mentions the > equals() method which is anyway defined for > each Object? Because Comparator is adding additional constraints onto the equals method.
 Signature Dale King
Roedy Green - 28 Jul 2005 06:30 GMT On 27 Jul 2005 02:08:23 -0700, "HK" <pifpafpuf@gmx.de> wrote or quoted
>Does anyone have an idea why the interface >java.util.Comparator explicitly mentions the >equals() method which is anyway defined for >each Object? I guess they are just trying to remind you to implement it. IT compares Comparators, not Strings or whatever you are sorting.
 Signature Bush crime family lost/embezzled $3 trillion from Pentagon. Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video. http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green. See http://mindprod.com/iraq.html photos of Bush's war crimes
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|