7 Replies Latest reply: May 6, 2012 12:39 PM by 935199 RSS

    "Elevating" generics in subclasses

    935199
      Hi!

      I'm trying to figure out a nice way to "elevate" generics in parent classes to something more specific in subclasses. Let me explain.

      I have a class callled LazyTreeNode that has a field of type List<LazyTreeNode>. I have public methods such as public LazyTreeNode getChild(int index). Now, if I make a subclass, say ImageTreeNode, I want the public methods that accept and return LazyTreeNodes to instead enforce accepting ImageTreeNodes or returning more specifically ImageTreeNodes.

      How can I do this? I can of course override all the methods and call super.methodName() but I'm thinking there must be a cleaner solution, because then you have to cast upwards. The whole point of generics (in my opinion) is to never have to cast upwards (explicitly), which I consider ugly. Any ideas?

      Thanks!
        • 1. Re: "Elevating" generics in subclasses
          EJP
          See java.util.Comparable and its uses. It does exactly that.
          • 2. Re: "Elevating" generics in subclasses
            935199
            I'm sorry, could you explain further? What I've used Comparable<> before is to allow objects to be sorted (java.lang one, I'm assuming). An example would be helpful: allow me to provide some sample code:
            public class Foo {
                protected List<Foo> myFoos;
            
                public Foo get(int index) {
                    return myFoos.get(index);
                }
            
                public void add(Foo foo) {
                    myFoos.add(foo);
                }
            }
            
            public class Bar extends Foo { // class should have list of Bars instead!
                // ...
            }
            
            public class Main {
                public static void main(String[] args) {
                    Bar bar = new Bar();
                    bar.add(new Bar()); // OK! 
                    bar.add(new Foo()); // Should return a compile-time error!
                    bar = bar.get(3); // Will throw compile-time casting error - should accept!
                }
            }
            What would I do to achieve the desired behaviour in the comments, without having to cast upwards?
            • 3. Re: "Elevating" generics in subclasses
              EJP
              Look at how it's declared. Comparable<T extends Comparable<T>>. That gives it T as the actual Comparable type for use within the class body. So the compareTo() method can take a T, not just a Comparable, and if there was a method that returned anything it could return T instead of Comparable. This is exactly what you want.
              • 4. Re: "Elevating" generics in subclasses
                935199
                Brilliant. I think I tried a similar solution in a previous, unrelated project, but the compiler complained about a wildcard in the parametrization declaration, so I must have believed declaring them like that was impossible. Marking as helpful, will check the syntax in my own project and report - thanks a million!
                • 5. Re: "Elevating" generics in subclasses
                  935199
                  I stumbled across a problem. Here's what my structure was, loosely:
                  public class Foo<T extends Foo<T>> {
                      protected List<T> myFoos;
                   
                      public T get(int index) { // fine!
                          return myFoos.get(index);
                      }
                   
                      public void add(T foo) { // fine!
                          myFoos.add(foo);
                      }
                  
                      public void addMyselfToFoos() {
                          myFoos.add(this); // compile error, because "this" is not considered a T, but it should be...?
                      }
                  }
                   
                  public class Bar extends Foo {
                      // ...
                  }
                  Any help is greatly appreciated.
                  • 6. Re: "Elevating" generics in subclasses
                    EJP
                    You'll have to cast. At least the problem is inside the class.
                    • 7. Re: "Elevating" generics in subclasses
                      935199
                      Too bad - I guess my dreams of a cast-free Java have to be put to rest. At least for the moment. Thanks for your help!