简体   繁体   中英

problems invoking a method with a generic type argument

I have some problem with generics, let me explain.

I have a class which wraps a LinkedList:

public class IdnList<T extends Numerable> extends IdnElement implements List<T> {

    private LinkedList<T> linkedList;

    @Override
    public boolean add(T e){
       return linkedList.add(e);
    }

   //stuff  
}

please note that the generic type T of this class extends the Numerable interface.

Ok, now inside a different class I want to invoke this method as follows:

 if(childToAdd instanceof Numerable)
 ((IdnList<?>)this).add((Numerable)childToAdd);

but eclipse says: The method add(capture#1-of ?) in the type IdnList<capture#1-of ?> is not applicable for the arguments (Numerable) , and I really can't figure out why it can't work. Why can't I add a Numerable object to my list? What am I missing?

EDIT: it's a classic. You ask, and then you find a clue. It seems a workaround is:

  ((IdnList<Numerable>)this).add((Numerable)childToAdd);

but I don't know how elegant it is. I really appreciate further comments.

Say you have classes A and B that both extend Numerable . Then there are three valid types of IdnList : IdnList<A> , IdnList<B> , and IdnList<Numerable> .

I hope you would agree that you shouldn't be able to add any Numerable to an IdnList<A> .

Now, in this line of code, how does the compiler know whether you've matched up the types correctly?

(IdnList<?>)this).add((Numerable)childToAdd);

All it knows is that childToAdd is a Numerable , and that this is some kind of IdnList . It doesn't know what kind, so it can't guarantee type safety. Remember that generic type checking is done entirely at compile time, not runtime.

I see how the workaround allows the code to compile, but I'm not sure what the risks of it are. It seems to me that since the generic type parameters are erased at runtime, essentially you're just bypassing all type checking here.

The problem lies in the reference to the instance of the IdnList in your other class. I cannot see it in your code example, but it appears that it does not have the proper type associated with it, especially not when it is being cast to a wildcard.

Since the IdnList requires a type (T) set per instance, there is no way for the compiler to know what you are trying to do.

If your reference to your IdnList has the proper type associated with it, it will accept any subclass of T, like so:

  IdnList<Numerable> list = new IdnList<Numerable>();
  list.add(new Numerable());
  list.add(new AnotherType());
  list.add(new YetAnotherType());

(Given that AnotherType and YetAnotherType are subclasses of Numerable)

Since you do not have any type set on the reference to your instance, I am guessing that what you are actually trying to do is this:

public class IdnList extends IdnElement implements List<Numerable> {

    private LinkedList<Numerable> linkedList;

    @Override
    public boolean add(Numerable e) {
        return linkedList.add(e);
    }
}

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