Search code examples
javagenericsscjpocpjp

Java Generic method/parameter types


In the following code example:

interface Eatable{ public void printMe();}
class Animal { public void printMe(){System.out.println("Animal object");}}
class Dog extends Animal implements Eatable{ public void printMe(){System.out.println("Dog object");}}
class BullTerrier extends Dog{ public void printMe(){System.out.println("BullTerrier object");}}

public class ZiggyTest{

    public static void main(String[] args) throws Exception{

        Object[] objArray = new Object[]{new Object(), new Object()};
        Collection<Object> objCollection = new ArrayList<Object>();

        Animal[] animalArray = new Animal[]{new Animal(),new Animal(),new Animal()};
        Collection<Animal> animalCollection = new ArrayList<Animal>();      

        Dog[] dogArray = new Dog[]{new Dog(),new Dog(),new Dog()};
        Collection<Dog> dogCollection = new ArrayList<Dog>();

        System.out.println(forArrayToCollection(animalArray,animalCollection).size());
        // System.out.println(forArrayToCollection(dogArray,dogCollection).size());  #1 Not valid

        System.out.println(genericFromArrayToCollection(animalArray,animalCollection).size());
        System.out.println(genericFromArrayToCollection(dogArray,dogCollection).size());  


        System.out.println(genericFromArrayToCollection(animalArray,objCollection).size()); //#2 
        System.out.println(genericFromArrayToCollection(dogArray,animalCollection).size()); //#3 
        // System.out.println(genericFromArrayToCollection(objArray,animalCollection).size()); //#4

    }

    public static Collection<Animal> forArrayToCollection(Animal[] a, Collection<Animal> c){
        for (Animal o : a){
            c.add(o);
        }

        return c;
    }

    static <T> Collection<T> genericFromArrayToCollection(T[] a, Collection<T> c) {
        for (T o : a) {
            c.add(o); 
        }

        return c;
    }

}

Why does the compiler allow the call to the genericFromArrayToCollection() method only if the declared type of the collection is the parent of the declared type of the array (See lines marked #2, #3 and #4) . Why is this please?

Thanks

Edit

When i uncomment the line marked #4 i get the following error

ZiggyTest.java:34: <T>genericFromArrayToCollection(T[],java.util.Collection<T>) in ZiggyTest cannot be applied to (java.lang.Object[],java.util.Collection<Animal>)
                System.out.println(genericFromArrayToCollection(objArray,animalCollection).size()); //#4
                                   ^
1 error

Edit 2

@Tudor i tried the following method using this statement

System.out.println(method1(new ArrayList<String>()).size());

The compiler complained with an error saying that cannot be applied to java.util.ArrayList

public static Collection<Object> method1(ArrayList<Object> c){
        c.add(new Object());
        c.add(new Object());        
        return c;
}

Solution

  • To answer your question, let's first establish the premise: we know that if you have a method taking an array as a parameter, you can pass an array of a subtype:

    public void method(Object[] list) // can be called with String[]
    

    but the reverse is not true:

    public void method(String[] list) // cannot be called with Object[]
    

    Then, it boils down to how the parameters of a generic method are actually instantiated, that is how the parameter type inference works. In your case #3, it is inferred to Animal, so the method declaration really looks like:

    static Collection<Animal> genericFromArrayToCollection(Animal[] a, 
                                                           Collection<Animal> c) {
    

    and since Dog is a subtype of Animal, it can fit nicely instead of the Animal[] array. Same for case #2.

    However, in case #4, the type is inferred to be Animal again, so the method looks like above, but you cannot put an Object[] array in place of an Animal[] array because Object is not a subtype of Animal.