简体   繁体   中英

How to compare two objects without knowing their type

I'm implementing a sorted list class , in this class i'm going to sort any kind of objects , so now i want to test if the object is comparable or not ,

i used this code to override the compareTo() method :-

class MyObject implements Comparable {

Object ob;

    MyObject(){
        this.ob=new Object();
    }

    public int compareTo(Object current){
        if((ob.toString().compareTo(current.toString()))>1)
        return 1;
        else if((ob.toString().compareTo(current.toString()))<1)
        return -1;
        else
        return 0;

    }

    public String toString(){

        return (String)ob;
    }
}

so now i need to assign numbers to these objects like this

class SortedListTest{
    public static void main (String arg[]){

        MyObject b1= new MyObject();
        MyObject b2= new MyObject();

        b1.ob=6;
        b2.ob=3;

        System.out.println(b2.compareTo(b1));
    }

}

but it keeps giving me this exception:-

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

Conceptually, that simply doesn't make sense!

The point is: when you allow arbitrary types of objects within your list, then the concept "sorting" does not make any sense here.

Thus the short answer is: forget about it.

Technically, your problem is here:

return (String)ob;

That code assumes that obj is a String. But as you allow for any kind of Object, that isn't necessarily true. So obj.toString() would prevent that runtime problem, but; as said: solving that technical problem isn't the real answer.

Lets step back to a real world example: assume you are asked to sort the things on your table: spoon, knife, cup, banana, apple. How do you intend to do that?

If at all, you could retract on something that all have in common; like "weight" for example. So you put all things on a scale; and use that to "sort" them.

From a Java perspective, the only thing that objects have in common would be a String representation (when calling toString() on them) or a numerical value (when calling hashCode() ). Thus you could "sort" on those properties. Which would work, but not result in anything even remotely useful.

In other words: when you intend to sort the content of your list, then there is no other way but allowing only the "same kind of objects" within your list. That is the reason why the java collections exactly work that way. In the sense of: one uses generics to express that List<T> contains objects that have some common type. From a conceptual point of view, that simply means: instead of allowing anything to go into a specific list, you only allow objects that "have something in common".

The problem you're reporting is that

return (String)ob;

should be

return ob.toString();

if ob is never null; or

return Objects.toString(ob);

if it might be.


But note that wrapping an object in an object to compare its toString() isn't necessary. You can simply use a Comparator<Object> , like Guava's Ordering.usingToString() :

int order = Ordering.usingToString().compare(someObject, someOtherObject);

or whatever the Java 8 equivalent is. I guess it would be something like:

Comparator<Object> usingToString = (a, b) -> a.toString().compareTo(b.toString());
int order = usingToString(someObject, someOtherObject);

Sorting objects without knowing their types doesn't make sense in many cases. However, there might be situations where you want to group objects by type etc. (although a different type of storage like a map etc. might be better suited for such cases).

The problem is that without knowing the objects' types you are limited in what you can do. Your comparator could do the following though:

  • Check if the objects being compared implement Comparable and call the compareTo() method on one.
  • If they are of the same type/class then they might be equal or not (depending on your requirements). How to compare those depends on you.
  • If the types are different you could try to compare by class name etc.

That being said you should really think about whether you actually need that as it's hard to do with the little information you can rely on.

In Java, and int is a primitive type. Primitive types do not have methods. So when you do this.

b1.ob = 6;
b2.ob = 3;

You are putting an int into your MyObject class in its ob variable. In the compareTo(Object current) method, you call the toString() method on ob . Since you gave ob an int, you cannot call any methods on it ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM