6

Is there anyway I can define a sequence/order for all objects in a JVM so that for any two distinct objects o1 or o2, there's a well defined rule that says either o1 > o2 or o2 > o1 and o1 == o2 if and only if they are the same object?

identityHashCode() comparison would be a good candidate, if there's a no-collision guarantee (there isn't).

Birth time would work too - if I can somehow obtain that.

Any ideas?

Thank you!

RAY
  • 6,810
  • 6
  • 40
  • 67
  • By the way, if you need an ordering just to add objects to TreeMap, then you can use HashMap instead (you just need equals method to compare objects by their references; luckily, this is behaviour by default). HashMap has most of TreeMap functionality but doesn't need ordering. – Ha. Apr 12 '11 at 12:23
  • Good thinking, but this won't work for two reasons: a. I need sequences, but hashmap by definition doesn't preserve order b. I need to sort "arbitrary" objects - implying some of them may actually have equals() overriden. – RAY Apr 12 '11 at 13:57
  • Then you can solve your general problem by wrapping all objects in some class that holds its creation number before adding them to TreeSet. Then you can compare this wrapper objects by this creation number with the condition that wrapper objects with the same reference (but possibly different creation number) are equal. – Ha. Apr 12 '11 at 15:29
  • Thanks. I'm not looking to add things into a TreeSet. A well-defined order is all I need. This question has already been resolved. (See below). The idea is to use identityHashcode() as first-level compare, and use a Weak-keyed referenceMap from Object to ID to resolve collissions of identityHashCode(). – RAY Apr 13 '11 at 09:40

5 Answers5

3

If you are in a position to maintain your own repository of objects, you could use a WeakHashMap<Object, Long> to maintain your own serial IDs.

Jim Blackler
  • 22,946
  • 12
  • 85
  • 101
  • [Here's an implementation](https://code.google.com/p/dellroad-stuff/source/browse/trunk/src/java/org/dellroad/stuff/java/ObjectComparator.java) of this idea. – Archie Nov 07 '14 at 19:42
2

All you need to do is define an arbitrary stable ordering. (Your "object birth time" is one such idea, but I don't think it is stored).

Method1: For any two objects of the same exact type, you can define such an ordering by comparing their individual fields. If all fields are identical, the objects are equal; if not, some field f is different and you can define the ordering based on the underlying type. If you have two objects with different types, simply use the type name to define the order; the one whose name is lexicographically smaller is "less than". You can implement a compare-per-type (might be a lot of work) or you can likely implement a generic compare the uses reflection to enumerate field names and types (to enable type-specific compares), although this might be pretty slow.

Method2: Any time you call your comparator, cache any object not yet encountered in a linear array. Any objects thus compared now have a index position in the array; o1 < o2 if the index(o1) < index(o2). You might need a hash table to associate assigned index positions with cached objects.

Method3: If you are working with a specific subset of the objects, and there's a canonical spanning tree, then number each edge of the spanning tree such that children arcs have unique numbers. Then o1 < o2 if the path to o1 from the root of the spanning tree, is less than the path to o2.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
  • Thanks! Method 1 won't work (fields equals doesn't mean reference equal, plus I need to be able to compare arbitrary objects, so I may not know the inside-workings of the objects). – RAY Apr 11 '11 at 08:29
  • But Method 2 is exactly what I need I think. I should use identityHashCode() as a first pass compare, and only store in in my comparator if identityHashcode clashes (which hopefully happens very infrequently). – RAY Apr 11 '11 at 08:30
  • @RAY, glad you liked Method2 and hope your optimization works out. What's the problem with Method1 equal references? If they are equal, pick another field to decide the ordering. If they are unequal, well, you need to compare the objects they reference to get the ordering. That process might be recursive (that's just code, so what?), and might cycle back to the original object (n which case they're equal). I don't see a problem in principle. – Ira Baxter Apr 11 '11 at 08:37
  • the question is a very general one, so I'm not looking to apply it to any particular time, so I can't really enumerate all possible types. Also, for two Object objects with no additional fields, I'd eventually still have to fall back to Method 2, wouldn't I? Or am I missing something here? Thanks again for your great help! – RAY Apr 11 '11 at 08:52
  • @RAY: You're right about two Object objects; you have to find a non-Method1 method :-}. Actually, for any pair of objects whose fields are equal you have this problem. Well, good thing there's Method2 to fall back on :-} – Ira Baxter Apr 11 '11 at 09:01
1

You need to implement Comparable<YourObject> interface and the compareTo(YourObject obj) method. The contract of the compareTo(..) method is to return -1(-ve number) when this object is smaller than the object passed as parameter, 0 when they are equal and +1 (+ve number) when this object is greater than the other object. You can implement the compare to using any fields that you like.

Using Collections.sort() or any list.sort() would using this comparator to sort your list.

Hope this helps!

aseychell
  • 1,794
  • 17
  • 35
  • 2
    He wants to define order for "all objects" in JVM, so basically he couldn't implement Comparable interface for all those objects? – Tommy Siu Apr 11 '11 at 07:35
  • 1
    I don't think the question is that basic. I think he wants a guarantee of consistent order of all VM objects. – Jim Blackler Apr 11 '11 at 07:43
0

If your objects are of the same type, you can remember their creation number in the constructor:

class A {
    private static long count = 0;
    private long objNumber;
    public A() {
        synchronized(A.class) {
            objNumber = count;
            count++;
        }
    }
}
Ha.
  • 3,454
  • 21
  • 24
  • 1
    there's really no need to reinvent the weel here. What you're looking is *AtomicInteger* (or *AtomicLong*) and its *incrementAndGet* method. – SyntaxT3rr0r Apr 11 '11 at 08:44
  • Thanks. I haven't used atomic operations before and this thought haven't crossed my mind. Now I would try to use them instead of synchronized where possible. – Ha. Apr 12 '11 at 12:19
0

The Object.toString() method should return different values for different objects in format:

getClass().getName() + '@' + Integer.toHexString(hashCode())

So could you compare the getClass().getName() alphabetically first, then the hashCode()?

Tommy Siu
  • 1,265
  • 2
  • 10
  • 24
  • 1
    I was thinking along those lines, but it's still only closer to 100% uniqueness, not guaranteed. – Jim Blackler Apr 11 '11 at 07:44
  • 2
    hashCodes can coinside - that is the problem RAY is trying to solve. – Ha. Apr 11 '11 at 07:44
  • 1
    Doesn't strictly satisfy RAY's criteria "o1 == o2 only if they're the same object". 64-bit JVMs may allow more than 232 objects, which implies hash code collision. – rlibby Apr 11 '11 at 07:53