1
public class Abc {

    public void process(List<A> a) {        

    }

    public static void main(String[] args) {
        Abc a = new Abc();
        List<A> alist = new ArrayList<A>();
        List<B> blist = new ArrayList<B>();
        List<C> clist = new ArrayList<C>();
        a.process(clist);
    }
}

    class A {

    }
    class B extends A {

    }
    class C extends  B {

    }

Why compilation issue with this code ? As per Object Oriented programming, there should not be any issue with this

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
Sushant Kumar
  • 159
  • 4
  • 14

4 Answers4

2

Even though C is a subclass of A, List<C> is not a subclass of List<A>, hence your compilation problem.

It's a common confusion among generics, but in plain terms, the problem is as above.

Try modifying your function signature as

public void process(List<? extends A> a)

That <? extends A> thing is a bounded wildcard. The use of these wildcards is just for these kinds of problems, where you need to match any class upper bounded by the A class you need. Read more about it here.

Bear in mind, however, that this imposes some restrictions to your List <? extends A> parameter. For example, you cannot add new elements to your list (except for null), because Java does not know the actual type of <? extends A> (can be B, C or what have you), and hence it completely prevents you from doing that kind of thing.

webuster
  • 2,490
  • 18
  • 27
2

A banana is a fruit. A list of bananas is not a list of fruit.

If it were you could put an apple in a list of bananas. Which would be strongly counter intuitive.

It's worth reading up on co and contra-variance, and perhaps checking out this SO answer about such issues and the PECS mnemonic. In your example above your list is a provider and so your method signature should take a List<? extends A>

Community
  • 1
  • 1
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
1

That's called co-variance, and it's not safe.

The problem is that if that were legal, than your Process class could put Bs into your List<C>

0

To add to the other answers.

If the above was allowed in Java, then you could write the following:

     public void process(List<A> a) {        
         a.Add(new A());
     }

     public static void main(String[] args) {
        Abc a = new Abc();
        List<A> alist = new ArrayList<A>();
        List<B> blist = new ArrayList<B>();
        List<C> clist = new ArrayList<C>();
        a.process(clist);
        for ( C c : clist){
           System.out.println(c.Name);
        }
    }


    class A {

    }
    class B extends A {

    }
    class C extends  B {
      String Name = "Class C";
    }

Since the body of the process method is expecting a List of type A, adding an object of type A to the list seems like a perfectly valid thing to do.

However other pieces of code which have reference to this list might believe this to be a list of C since it was originally defined as that.

Now if they try to access a property that exists in only C ( e.g. Name in the above example)objects, the code will break.

In the code above if subclasing was allowed as you wanted, we would reach an invalid state in terms of the type system of the program. Hence this is not allowed in Java

Osama Javed
  • 1,432
  • 1
  • 16
  • 21