stacker
stacker

Reputation: 68942

How can I have instances of Base and Sub-Classes in one List?

I'm currently facing an issue with base and subclasses.

While having a single object as parameter (method single) the compiler doesn't complain.

But if it comes to lists the compiler forces me to declare the list as <? extends Base>

After that I'm no longer allowed to add objects of the base type to that list.

How can I use both types (Base and Subclass) in one list?

public class Generics {

    class Base {    }

    class Sub extends Base{     }

    interface I {
        public void list( List<Sub> list );
        public void single( Sub p);
    }

    class C implements I {
        public void list( List<Sub> list) {     }
        public void single( Sub p) {        }
    }

    void test() {
        C c = new C();
        c.single( new Sub() );
        c.list( new ArrayList<Base>() ); // The method list(List<Generics.Sub>) in the type Generics.C is not applicable for the arguments (ArrayList<Generics.Base>)

    }

    public static void main( String[] args) {
        Generics g = new Generics();
        g.test();
    }
}

Upvotes: 0

Views: 136

Answers (3)

Kumar Vivek Mitra
Kumar Vivek Mitra

Reputation: 33534

Below are the 2 ways to do it....

public void inTake(List<? extends Base> list){

}

Or

public T extends Base void inTake(List<T> list){

}

Upvotes: 1

Brian
Brian

Reputation: 17309

Change:

public void list(List<Sub> list);

to:

public void list(List<? extends Base> list);

Using just List<Base> will give you compiler errors like this one:

public static void main(String[] args) {
    List<Sub> subs = new ArrayList<Sub>();
    doSomethingWith(subs); // The method doSomethingWith(List<Base>) in the type Main is not applicable for the arguments (List<Sub>)
}

private static void doSomethingWith(List<Base> bases) {
    // Do something with bases
}

If all you're going to pass is List<Base> to doSomethingWith, then this point is moot, since this won't give you a compiler error. If you want to pass lists that are of a specific type (such as List<Sub> above), then you need to change doSomethingWith to:

private static void doSomethingWith(List<? extends Base> bases) {

This fixes the problem. You could also do it at the caller lever (but it's a bit messier):

    List<Sub> subs = new ArrayList<Sub>();
    doSomethingWith(new ArrayList<Base>(subs));

One issue with the wildcard (?) approach is that you can't add new items to the list. To do that, you need something like:

private static <B extends Base> void doSomethingWith(List<B> bases) {

And then add only B instances to bases.

Upvotes: 1

Keppil
Keppil

Reputation: 46209

Just declare all your lists as

List<Base> list;

Then you can add both Base objects and objects of any subclass.

Upvotes: 1

Related Questions