1

Why go method gives me a compile time exception even if Animal is parent class of Dog ?

class Animal{}

class Dog extends Animal{}

class Sample { 
    void go(ArrayList<Animal> list){}   

    public static void main(String...args)
    {
       ArrayList<Dog> list=new ArrayList<Dog>();
       new Sample().go(list);
    }
} 

This gives me a compile time error why?

Olimpiu POP
  • 5,001
  • 4
  • 34
  • 49
  • 7
    A mutable list of `Animal` can have more operations performed on it than a mutable list of `Dog` (for example, inserting `Animal`s that are not `Dog`s), and therefore `ArrayList` is not a valid subtype of `ArrayList`. – Mankarse Mar 07 '14 at 07:52
  • @Mankarse: this should be an answer. – JB Nizet Mar 07 '14 at 07:59
  • possible duplicate of [Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?](http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p) – Ingo Mar 07 '14 at 08:46

4 Answers4

1

Although it is a bit unintuitive, generic is not covariance in Java.

Which means, even Dog is-an Animal, List<Dog> is NOT a List<Animal>. (However Dog[] is-an Animal[], just to further confuse you LOL ).

Normal way to deal with the problem is to make use of wildcard in generics, for example, change your go() to void go(List<? extends Animal> list){}.

Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
0

As Mankarse stated:

A mutable list of Animal can have more operations performed on it than a mutable list of Dog (for example, inserting Animals that are not Dogs), and therefore ArrayList<Dog> is not a valid subtype of ArrayList<Animal>.

This is a general characteristic of generics, as the rules of normal inheritance dont apply on generic type parameters. A more detailed explanation on this can be found here.

To circumvent this problem, you can use generic wildcards. For example a method with the signature perform(List<? extends Animal> animals) allows passing a list with a generic type parameter of anything that extends Animal - for example Dog.

On the other side perform(List<Animal> animals) only allows passing a list with the Animal type parameter.

maxdev
  • 2,491
  • 1
  • 25
  • 50
0

Generics restrict you to pass only same type of parameter that define in method definition. Below solution will work for you.

import java.util.ArrayList;

class Animal{}

class Dog extends Animal{}

public class Sample {

void go(ArrayList<? extends Animal> list){}

public static void main(String...args) {

ArrayList<Dog> list=new ArrayList<Dog>(); new Sample().go(list); }}

Haroon
  • 127
  • 1
  • 6
-1

As Mankarse already pointed out, you cannot let ArrayList<Animal> be a supertype of ArrayList<Dog> since it allows inserting elements.

If you would use a read-only collection/interface (don't know what this would be in java), then it should be possible.

Onur
  • 5,017
  • 5
  • 38
  • 54