0

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

  • Relevant: http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – Andy Turner Jan 20 '17 at 08:28
  • Please read the documentation on `compareTo()` then think about this line: `if((ob.toString().compareTo(current.toString()))>1) return 1;` - `String.compareTo()` will most probably return 1 if the first string is greater but your condition checks for _greater than_ 1, i.e. it would not be true in any case. – Thomas Jan 20 '17 at 08:34

4 Answers4

6

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

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • What if the `toString` of spoons, knifes, cups, etc return strings like "Spoon big", "Spoon small", "knife bread", "knife butter", "knife butcher", "cup red big", "cup blue small" etc. Suddenly you can sort a collection of all household items by their type and specific attributes without the need to create a collection for each object and change the code every time you add a new object type. OPs example might be unpractical in a real world situation but it could be a decent school lesson, especially if we replace `Object` with something like `AbstractItem` – Alexandru Severin Jan 20 '17 at 08:51
  • @AlexandruSeverin The *if* in your comment is the problem. When you allow arbitrary objects, you have **no** idea how there string representation will look like. Probably it will often more look like "someclass@hash". How do you sort that. But point taken; I will update my answer accordingly. – GhostCat Jan 20 '17 at 08:53
3

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);
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • You mean `Objects.toString(Object o [, String nullDefault])` i guess ? Didn't knew that class. – AxelH Jan 20 '17 at 08:35
1

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.

Thomas
  • 87,414
  • 12
  • 119
  • 157
-2

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;

Michael Sharp
  • 496
  • 3
  • 10
  • The short version of Andy comment, the `int` will be autoboxed into `Integer` to fit in the `Object` variable – AxelH Jan 20 '17 at 08:37