0

I have a class TreeNode:

public abstract class TreeNode<T>{
   .
   .
   .

    public Collection<TreeNode<T>> children;

    public void clear(){
       if(children == null) 
      return;

       Iterator<TreeNode<T>> iterator = children.iterator();
       while(iterator.hasNext()){
          TreeNode<T> node = iterator.next();
          node.clear();
       }

       children.clear();
   }
   .
   .
   .

}

I then have a class ListTreeNode:

public class ListTreeNode<T> extends TreeNode<T>{
   .
   .
   .

   public ListTreeNode(T data, List<ListTreeNode<T>> children){
      this.data = data;
      this.root = null;
      this.children = children;
      this.childIndex = 0;
   }

   .
   .
   .

}

I get a compiler error saying that I cannot convert from List<ListTreeNode<T>> to Collection<TreeNode<T>>. Shouldn't I be able to, since List is a subinterface of Collection and ListTreeNode is a subclass of TreeNode? Also, I have a corresponding class SetTreeNode which uses Set instead of List and there are no errors in its corresponding constructor where I have this.children = children; .

Eliezer
  • 7,209
  • 12
  • 56
  • 103
  • 2
    I don't really see why you have to pass a List> and not List>, is this really intentional? That said, since ListTreeNode extends TreeNode, List> is not assignable to Collection> but rather Collection extends TreeNode> – misberner Nov 09 '11 at 21:25
  • @DylanSmith: Except that one deals with C#, and this question deals with Java. (Although the answers are similar, they're not identical.) The first duplicate I could find is [this one](http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicit), but I'm sure there are many more. – Daniel Pryden Nov 09 '11 at 21:27
  • ugh, didn't notice the Java...nevermind – Dylan Smith Nov 09 '11 at 21:29
  • I intentionally passed in a List> so that you cannot pass in any other class that derives from TreeNode. I originally changed children to Collection> but I got some warnings from that. So I changed it to Collection extends TreeNode> and that got rid of the warnings. Thanks :) – Eliezer Nov 09 '11 at 21:34

2 Answers2

2

A List<String> is not a List<Object>. If it were, you could be able to do this:

List<String> listOfStrings = new ArrayList<String>();
List<Object> listOfObjects = listOfStrings;
listOfObjects.add(new Integer(3));

As you see, this would ruin the type-safety of generic collections.

You should probably use a Collection<? extends TreeNode<T>>

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

This problem has nothing to do with casting a List<T> to a Collection<T>, and everything to do with casting a List<SomeDerivedClass> to a List<SomeBaseClass>. Java generics are invariant, and the behavior you are looking for is covariance.

This question has been raised many times on StackOverflow before. Here is one example: Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

Community
  • 1
  • 1
Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135