views:

41

answers:

1

Hello everyone!

My goal is very simple today, I am trying to work out the proper way to implement compareTo (or the Comparable) interface for my class which extends DefaultMutableTreeNode.

The problem is this: Say I have a perfectly good class that represents times. I've already written a perfectly good compareTo method (which works as I desire) that I've tested out with Arrays.sort() with marvelous results.

Now lets say I have a JTree with bunches of different objects, like this:

    new SpecialNode("Zomg a string!"); // add this group of nodes right here
    new SpecialNode(new Time("8:55 PM"));
    new SpecialNode(new SomeTypeYouveNeverHeardOf());

So, being a professional programmer, I immediately start coding without any forethought whatsoever. Here is my SpecialNode class:

class SpecialNode extends DefaultMutableTreeNode implements Comparator<SpecialNode>
{
    public int compareTo(SpecialNode sn)
    {
        // Not only does this not work correctly (read: at all)
        // But, it is sub-par, how do I get the type information out of the userObject
        // So I can cast it correctly and call the correct compareTo method!!
        return this.getUserObject().toString().compareTo(sn.getUserObject().toString());
    }
}

Ok, so if you didn't read the comments (which, admit, you didn't); My problem is that within the compareTo method of SpecialNode, I only have access to the userObject. Sadly, I do not know what the userObject used to be, and as such, I cannot properly cast it to call the correct compareTo method!

This is really a pain, since I've already written several perfectly good compareTo methods in all of the classes which will be added to my tree. So can someone help a guy out and drop me a hint?

tl;dr - How do I get type information out of an generic object that DefaultMutableTreeNode stores? If that is not possible, how should I go about comparing two instances of SpecialNode when I don't even know what they may contain!

Thanks in advance.

A: 

I'm assuming you can't have a TreeNode for each type of data. Does it make sense in your use case to do comparisons if the type is different?

Ideas:

  1. Can SimpleNode know all of the possible types and do instanceof and casts to the correct type for Comparable? This is the way I would have handled it a few years ago.

  2. How do you feel about unchecked warnings? I had a similar problem before using a JList and couldn't quite make the compiler happy (I gave up the swing default model to make my life easier). Maybe someone else could improve on this answer?

    class SpecialNode<T extends Comparable<T>> extends DefaultMutableTreeNode 
                                              implements Comparable<SpecialNode>
    {
      T typedUserObject;
      SpecialNode(T t)
      {
         this.typedUserObject = t;
         setUserObject(t);
      }
    
    
      public int compareTo(SpecialNode node)
      {
          if(typedUserObject.getClass().isInstance(node.typedUserObject))
          {
              T otherObj = (T) node.typedUserObject;
              return typedUserObject.compareTo(otherObj);
          }
          else
          {
              //What are you going to do if they're not the same type?
              return -1;
          }
      }
    
    
    }
    

Edit: If you know they should be the same type - eliminates check

class SpecialNode<T extends Comparable<T>> extends DefaultMutableTreeNode
                                          implements Comparable<SpecialNode<T>>
{
  T typedUserObject;
  SpecialNode(T t)
  {
     this.typedUserObject = t;
     setUserObject(t);
  }


  public int compareTo(SpecialNode<T> node)
  {
     return typedUserObject.compareTo(node.typedUserObject);
  }    
}

If you don't want the code in the node itself (I don't think I would), you might create a separate class that implements Comparator<SpecialNode<T>>

Steve Jackson
Thank you for your prompt reply! That is a good answer, but it leaves me with a bad taste in my mouth. I can reasonably assume with my model, that whenever two SpecialNodes are compared, their userObjects will be of the same type. (In other words I'd probably throw an exception at your 'return -1' line.) But ideally I would really like to avoid switching based on type if possible. That type of programming never leads to maintainable code, at least in my experience.
Tommy Fisk