Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic: why use "class A <E extends Superclass>" in stead of "class B<Superclass>"?

Tags:

java

generics

I am experimenting with Java generics. I understand with Java generics we can create class and methods which only deals with specific types. This enable detection of programming error at compile time.

My question may sounds strange. Why use E extends Superclass instead of Superclass? Please take a look at the code below.

class Hunter <E extends Animal>{}

class Keaper <Animal>{}
    /*edit: as AR.3 and other pointed out, Keaper<Animal> is the same as Keaper<E>.
 Animal  is just a type parameter here*/

class Animal{}

class Cat extends Animal{}

class Dog extends Animal{}


public class TestGeneric {
    public static void main(String[] args) {
        Hunter<Cat> hunter1 = new Hunter<>();
        Hunter<Dog> hunter2 = new Hunter<>();
        Hunter<Animal> hunter3 = new Hunter<>();

        ArrayList<Hunter> hunters=  new ArrayList<>();
        hunters.add(hunter1);
        hunters.add(hunter2);
        hunters.add(hunter3);

        Keaper<Cat> keaper1 = new Keaper<>();
        Keaper<Dog> keaper2 = new Keaper<>();
        Keaper<Animal> keaper3 = new Keaper<>();
//Edit: as AR.3 and others pointed out, Keaper<String> is also legal here.

        ArrayList<Keaper> keapers=  new ArrayList<>();
        keapers.add(keaper1);
        keapers.add(keaper2);
        keapers.add(keaper3);
    }
}

I feel E extends Animal is almost the same as Animal, except the first one may provide more information. Any idea?

like image 853
Twisted Meadow Avatar asked Mar 13 '16 17:03

Twisted Meadow


1 Answers

Actually Animal as declared in the definition of the Keaper class is nothing but a type parameter (it would be more conventional to just use one letter for it, like Keaper<T>). So it's a completely different range of possible type arguments: the Keaper class can accept any type as parameter, not just Animals. You can write Keaper<String> and it will compile fine, which is clearly not what you want.

What you intended to do is not possible with generics: you cannot force a class to be generic with only one possible type argument ever associated with it. What you can do is limit the range of associated types to be, for example, any type that extends a certain type, which you already did with the Hunter class.

Also as mentioned in @JHH's comment, you should avoid using Keaper as a raw type in a list, otherwise the code would not be fully generic. Instead of ArrayList<Keaper> keapers = new ArrayList<>() you can write ArrayList<Keaper<? extends Animal>> keapers = new ArrayList<>().

like image 109
M A Avatar answered Oct 21 '22 18:10

M A