How to implement Comparable so it is consistent with identity-equalityHow do I efficiently iterate over each entry in a Java Map?How do I read / convert an InputStream into a String in Java?How do I generate random integers within a specific range in Java?“implements Runnable” vs “extends Thread” in JavaComparing Java enum members: == or equals()?How does a ArrayList's contains() method evaluate objects?How do I convert a String to an int in Java?equals() vs compareTo() in Comparator/able (Theoretical)What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?consequence of compare() method of Comparator interface not consistent with equals() method

Why was Sir Cadogan fired?

What is the opposite of "eschatology"?

How dangerous is XSS

Can a virus destroy the BIOS of a modern computer?

How to install cross-compiler on Ubuntu 18.04?

How seriously should I take size and weight limits of hand luggage?

Is it "common practice in Fourier transform spectroscopy to multiply the measured interferogram by an apodizing function"? If so, why?

What Exploit Are These User Agents Trying to Use?

How obscure is the use of 令 in 令和?

Can compressed videos be decoded back to their uncompresed original format?

Was the Stack Exchange "Happy April Fools" page fitting with the '90's code?

Can I hook these wires up to find the connection to a dead outlet?

How to travel to Japan while expressing milk?

Do Iron Man suits sport waste management systems?

Could the museum Saturn V's be refitted for one more flight?

Should I tell management that I intend to leave due to bad software development practices?

Ambiguity in the definition of entropy

What's the meaning of "Sollensaussagen"?

GFCI outlets - can they be repaired? Are they really needed at the end of a circuit?

Car headlights in a world without electricity

Why were 5.25" floppy drives cheaper than 8"?

One verb to replace 'be a member of' a club

Is this draw by repetition?

Did 'Cinema Songs' exist during Hiranyakshipu's time?



How to implement Comparable so it is consistent with identity-equality


How do I efficiently iterate over each entry in a Java Map?How do I read / convert an InputStream into a String in Java?How do I generate random integers within a specific range in Java?“implements Runnable” vs “extends Thread” in JavaComparing Java enum members: == or equals()?How does a ArrayList's contains() method evaluate objects?How do I convert a String to an int in Java?equals() vs compareTo() in Comparator/able (Theoretical)What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?consequence of compare() method of Comparator interface not consistent with equals() method













15















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.










share|improve this question
























  • 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
    yesterday






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    yesterday











  • 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
    yesterday











  • @RickyMo right.

    – Balz Guenat
    yesterday






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    yesterday















15















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.










share|improve this question
























  • 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
    yesterday






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    yesterday











  • 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
    yesterday











  • @RickyMo right.

    – Balz Guenat
    yesterday






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    yesterday













15












15








15


0






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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday









Peter Mortensen

13.9k1987113




13.9k1987113










asked yesterday









Balz GuenatBalz Guenat

4472419




4472419












  • 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
    yesterday






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    yesterday











  • 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
    yesterday











  • @RickyMo right.

    – Balz Guenat
    yesterday






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    yesterday

















  • 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
    yesterday






  • 3





    Which clause of the contract would be broken exactly?

    – Balz Guenat
    yesterday











  • 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
    yesterday











  • @RickyMo right.

    – Balz Guenat
    yesterday






  • 3





    @Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

    – Haem
    yesterday
















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
yesterday





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
yesterday




3




3





Which clause of the contract would be broken exactly?

– Balz Guenat
yesterday





Which clause of the contract would be broken exactly?

– Balz Guenat
yesterday













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
yesterday





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
yesterday













@RickyMo right.

– Balz Guenat
yesterday





@RickyMo right.

– Balz Guenat
yesterday




3




3





@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

– Haem
yesterday





@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

– Haem
yesterday












6 Answers
6






active

oldest

votes


















29














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.






share|improve this answer


















  • 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
    yesterday






  • 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
    yesterday











  • @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
    yesterday






  • 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
    yesterday






  • 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
    yesterday



















5














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 ids.



Since each instance has a different id, compareTo will never return 0.






share|improve this answer


















  • 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
    yesterday











  • @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
    yesterday






  • 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
    yesterday











  • @BalzGuenat good point.

    – Eran
    yesterday






  • 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
    yesterday



















5














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.






share|improve this answer

























  • You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    yesterday











  • @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
    yesterday


















0














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 on name

  • Implement compareTo() as follows:

public void compareTo(MyObject object) 
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());






share|improve this answer























  • 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
    yesterday











  • That is the reason why I advised overriding hashcode() and make it rely not just on name.

    – Darshan Mehta
    yesterday











  • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

    – Balz Guenat
    yesterday


















0














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.





share|improve this answer




















  • 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
    yesterday












  • @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
    yesterday






  • 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
    yesterday











  • @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
    10 hours ago











  • @Tezra "Made to work", agreed that the current solution is not going to be correct.

    – Voo
    9 hours ago


















0














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!");








share|improve this answer

























    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
    );



    );













    draft saved

    draft discarded


















    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









    29














    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.






    share|improve this answer


















    • 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
      yesterday






    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday






    • 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
      yesterday
















    29














    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.






    share|improve this answer


















    • 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
      yesterday






    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday






    • 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
      yesterday














    29












    29








    29







    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.






    share|improve this answer













    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.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered yesterday









    GhostCatGhostCat

    95.5k1794160




    95.5k1794160







    • 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
      yesterday






    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday






    • 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
      yesterday













    • 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
      yesterday






    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday






    • 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
      yesterday








    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
    yesterday





    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
    yesterday




    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
    yesterday





    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
    yesterday













    @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
    yesterday





    @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
    yesterday




    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
    yesterday





    @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
    yesterday




    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
    yesterday






    @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
    yesterday














    5














    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 ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer


















    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday











    • @BalzGuenat good point.

      – Eran
      yesterday






    • 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
      yesterday
















    5














    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 ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer


















    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday











    • @BalzGuenat good point.

      – Eran
      yesterday






    • 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
      yesterday














    5












    5








    5







    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 ids.



    Since each instance has a different id, compareTo will never return 0.






    share|improve this answer













    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 ids.



    Since each instance has a different id, compareTo will never return 0.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered yesterday









    EranEran

    291k37479563




    291k37479563







    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday











    • @BalzGuenat good point.

      – Eran
      yesterday






    • 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
      yesterday













    • 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
      yesterday











    • @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
      yesterday






    • 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
      yesterday











    • @BalzGuenat good point.

      – Eran
      yesterday






    • 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
      yesterday








    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
    yesterday





    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
    yesterday













    @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
    yesterday





    @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
    yesterday




    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
    yesterday





    "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
    yesterday













    @BalzGuenat good point.

    – Eran
    yesterday





    @BalzGuenat good point.

    – Eran
    yesterday




    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
    yesterday






    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
    yesterday












    5














    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.






    share|improve this answer

























    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      yesterday











    • @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
      yesterday















    5














    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.






    share|improve this answer

























    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      yesterday











    • @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
      yesterday













    5












    5








    5







    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.






    share|improve this answer















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    TezraTezra

    5,21321244




    5,21321244












    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      yesterday











    • @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
      yesterday

















    • You could explain where to get that UUID, and why collision isn't a (practical) problem.

      – Yakk - Adam Nevraumont
      yesterday











    • @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
      yesterday
















    You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    yesterday





    You could explain where to get that UUID, and why collision isn't a (practical) problem.

    – Yakk - Adam Nevraumont
    yesterday













    @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
    yesterday





    @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
    yesterday











    0














    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 on name

    • Implement compareTo() as follows:

    public void compareTo(MyObject object) 
    this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());






    share|improve this answer























    • 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
      yesterday











    • That is the reason why I advised overriding hashcode() and make it rely not just on name.

      – Darshan Mehta
      yesterday











    • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

      – Balz Guenat
      yesterday















    0














    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 on name

    • Implement compareTo() as follows:

    public void compareTo(MyObject object) 
    this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());






    share|improve this answer























    • 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
      yesterday











    • That is the reason why I advised overriding hashcode() and make it rely not just on name.

      – Darshan Mehta
      yesterday











    • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

      – Balz Guenat
      yesterday













    0












    0








    0







    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 on name

    • Implement compareTo() as follows:

    public void compareTo(MyObject object) 
    this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());






    share|improve this answer













    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 on name

    • Implement compareTo() as follows:

    public void compareTo(MyObject object) 
    this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered yesterday









    Darshan MehtaDarshan Mehta

    23.6k32955




    23.6k32955












    • 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
      yesterday











    • That is the reason why I advised overriding hashcode() and make it rely not just on name.

      – Darshan Mehta
      yesterday











    • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

      – Balz Guenat
      yesterday

















    • 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
      yesterday











    • That is the reason why I advised overriding hashcode() and make it rely not just on name.

      – Darshan Mehta
      yesterday











    • any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

      – Balz Guenat
      yesterday
















    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
    yesterday





    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
    yesterday













    That is the reason why I advised overriding hashcode() and make it rely not just on name.

    – Darshan Mehta
    yesterday





    That is the reason why I advised overriding hashcode() and make it rely not just on name.

    – Darshan Mehta
    yesterday













    any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

    – Balz Guenat
    yesterday





    any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.

    – Balz Guenat
    yesterday











    0














    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.





    share|improve this answer




















    • 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
      yesterday












    • @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
      yesterday






    • 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
      yesterday











    • @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
      10 hours ago











    • @Tezra "Made to work", agreed that the current solution is not going to be correct.

      – Voo
      9 hours ago















    0














    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.





    share|improve this answer




















    • 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
      yesterday












    • @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
      yesterday






    • 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
      yesterday











    • @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
      10 hours ago











    • @Tezra "Made to work", agreed that the current solution is not going to be correct.

      – Voo
      9 hours ago













    0












    0








    0







    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.





    share|improve this answer















    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.






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    Joop EggenJoop Eggen

    78.8k755105




    78.8k755105







    • 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
      yesterday












    • @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
      yesterday






    • 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
      yesterday











    • @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
      10 hours ago











    • @Tezra "Made to work", agreed that the current solution is not going to be correct.

      – Voo
      9 hours ago












    • 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
      yesterday












    • @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
      yesterday






    • 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
      yesterday











    • @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
      10 hours ago











    • @Tezra "Made to work", agreed that the current solution is not going to be correct.

      – Voo
      9 hours ago







    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
    yesterday






    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
    yesterday














    @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
    yesterday





    @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
    yesterday




    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
    yesterday





    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
    yesterday













    @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
    10 hours ago





    @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
    10 hours ago













    @Tezra "Made to work", agreed that the current solution is not going to be correct.

    – Voo
    9 hours ago





    @Tezra "Made to work", agreed that the current solution is not going to be correct.

    – Voo
    9 hours ago











    0














    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!");








    share|improve this answer





























      0














      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!");








      share|improve this answer



























        0












        0








        0







        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!");








        share|improve this answer















        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!");









        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 10 hours ago

























        answered 10 hours ago









        TezraTezra

        5,21321244




        5,21321244



























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

            Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

            What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company