How to implement Comparable so it is consistent with identity-equality
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
|
show 4 more comments
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
Apr 1 at 8:18
3
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
Apr 1 at 8:25
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40
|
show 4 more comments
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
java equals comparator comparable
edited Apr 1 at 18:46
Peter Mortensen
13.9k1987113
13.9k1987113
asked Apr 1 at 8:10
Balz GuenatBalz Guenat
4572419
4572419
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
Apr 1 at 8:18
3
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
Apr 1 at 8:25
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40
|
show 4 more comments
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
Apr 1 at 8:18
3
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
Apr 1 at 8:25
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
Apr 1 at 8:18
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
Apr 1 at 8:18
3
3
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Did you mean you want when
A
and B
have getName()
equal, you don't care whether A > B
or B > A
, but you want consistent result i.e. if for once A > B
is true, then A > B
is always true throughout the whole process lifetime?– Ricky Mo
Apr 1 at 8:25
Did you mean you want when
A
and B
have getName()
equal, you don't care whether A > B
or B > A
, but you want consistent result i.e. if for once A > B
is true, then A > B
is always true throughout the whole process lifetime?– Ricky Mo
Apr 1 at 8:25
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
3
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40
|
show 4 more comments
6 Answers
6
active
oldest
votes
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
Apr 1 at 8:23
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
Apr 1 at 14:59
|
show 6 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
Apr 1 at 8:37
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
|
show 8 more comments
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>{
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}
return antiuniverseProp.get(i);
}
@Override
public int compareTo(Test o) {
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}
}
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object) {
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
}
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other) {
return this == other;
}
@Override
public int compareTo(C other) {
...
if (this == other) {
return 0
}
if (super.equals(other)) {
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this)) {
return 1;
} else if (!collisions.contains(new Pair(this, other)) {
collisions.add(new Par(this, other));
}
return 1;
}
...
}
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
Apr 1 at 15:55
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
Apr 1 at 8:23
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
Apr 1 at 14:59
|
show 6 more comments
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
Apr 1 at 8:23
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
Apr 1 at 14:59
|
show 6 more comments
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
answered Apr 1 at 8:19
GhostCatGhostCat
95.9k1794161
95.9k1794161
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
Apr 1 at 8:23
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
Apr 1 at 14:59
|
show 6 more comments
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
Apr 1 at 8:23
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
Apr 1 at 14:59
8
8
A comparator seems like a non-broken solution. Even if the expectation of
Comparable
is that compare==0
only when the two objects are equal, a comparator does not have that expectation.– khelwood
Apr 1 at 8:23
A comparator seems like a non-broken solution. Even if the expectation of
Comparable
is that compare==0
only when the two objects are equal, a comparator does not have that expectation.– khelwood
Apr 1 at 8:23
2
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
Apr 1 at 8:38
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
Apr 1 at 8:46
1
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
Apr 1 at 12:15
1
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your
equals
consistent with compareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.– Voo
Apr 1 at 14:59
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your
equals
consistent with compareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.– Voo
Apr 1 at 14:59
|
show 6 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
Apr 1 at 8:37
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
|
show 8 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
Apr 1 at 8:37
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
|
show 8 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
answered Apr 1 at 8:16
EranEran
292k37481564
292k37481564
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
Apr 1 at 8:37
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
|
show 8 more comments
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
Apr 1 at 8:37
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
1
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
Apr 1 at 8:20
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the
id
would have to be serialized.– Eran
Apr 1 at 8:37
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the
id
would have to be serialized.– Eran
Apr 1 at 8:37
1
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
Apr 1 at 8:45
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
@BalzGuenat good point.
– Eran
Apr 1 at 8:47
1
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
Apr 1 at 10:07
|
show 8 more comments
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
add a comment |
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
add a comment |
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
edited Apr 1 at 16:02
answered Apr 1 at 14:57
TezraTezra
5,23321244
5,23321244
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
add a comment |
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
Apr 1 at 15:43
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
Apr 1 at 16:06
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>{
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}
return antiuniverseProp.get(i);
}
@Override
public int compareTo(Test o) {
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}
}
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>{
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}
return antiuniverseProp.get(i);
}
@Override
public int compareTo(Test o) {
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}
}
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>{
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}
return antiuniverseProp.get(i);
}
@Override
public int compareTo(Test o) {
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}
}
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>{
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i) {
while(antiuniverseProp.size() < i) {
antiuniverseProp.add(UUID.randomUUID());
}
return antiuniverseProp.get(i);
}
@Override
public int compareTo(Test o) {
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
}
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
}
}
edited Apr 2 at 19:02
answered Apr 2 at 18:51
TezraTezra
5,23321244
5,23321244
add a comment |
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object) {
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
}
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object) {
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
}
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object) {
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
}
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object) {
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
}
answered Apr 1 at 8:20
Darshan MehtaDarshan Mehta
23.6k32955
23.6k32955
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
add a comment |
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
Object.hashCode
has the same problem as System.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.– Balz Guenat
Apr 1 at 8:22
Object.hashCode
has the same problem as System.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.– Balz Guenat
Apr 1 at 8:22
That is the reason why I advised overriding
hashcode()
and make it rely not just on name.– Darshan Mehta
Apr 1 at 8:26
That is the reason why I advised overriding
hashcode()
and make it rely not just on name.– Darshan Mehta
Apr 1 at 8:26
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
Apr 1 at 8:33
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other) {
return this == other;
}
@Override
public int compareTo(C other) {
...
if (this == other) {
return 0
}
if (super.equals(other)) {
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this)) {
return 1;
} else if (!collisions.contains(new Pair(this, other)) {
collisions.add(new Par(this, other));
}
return 1;
}
...
}
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
Apr 1 at 15:55
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other) {
return this == other;
}
@Override
public int compareTo(C other) {
...
if (this == other) {
return 0
}
if (super.equals(other)) {
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this)) {
return 1;
} else if (!collisions.contains(new Pair(this, other)) {
collisions.add(new Par(this, other));
}
return 1;
}
...
}
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
Apr 1 at 15:55
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other) {
return this == other;
}
@Override
public int compareTo(C other) {
...
if (this == other) {
return 0
}
if (super.equals(other)) {
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this)) {
return 1;
} else if (!collisions.contains(new Pair(this, other)) {
collisions.add(new Par(this, other));
}
return 1;
}
...
}
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other) {
return this == other;
}
@Override
public int compareTo(C other) {
...
if (this == other) {
return 0
}
if (super.equals(other)) {
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this)) {
return 1;
} else if (!collisions.contains(new Pair(this, other)) {
collisions.add(new Par(this, other));
}
return 1;
}
...
}
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
edited Apr 1 at 15:55
answered Apr 1 at 8:40
Joop EggenJoop Eggen
78.9k755105
78.9k755105
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
Apr 1 at 15:55
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
add a comment |
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
Apr 1 at 15:55
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
1
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
Apr 1 at 15:44
@Yakk-AdamNevraumont true, just the mention of
static
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?– Joop Eggen
Apr 1 at 15:55
@Yakk-AdamNevraumont true, just the mention of
static
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?– Joop Eggen
Apr 1 at 15:55
1
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
Apr 1 at 16:31
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
Apr 2 at 19:18
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
Apr 2 at 19:27
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
Apr 1 at 8:18
3
Which clause of the contract would be broken exactly?
– Balz Guenat
Apr 1 at 8:21
Did you mean you want when
A
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?– Ricky Mo
Apr 1 at 8:25
@RickyMo right.
– Balz Guenat
Apr 1 at 8:31
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
Apr 1 at 9:40