0

Maybe can somebody help me understand better how generics work in Java.

I have "problems" in understanding this sample of code:

class Animal {}

class Dog extends Animal {}

class Cat extends Animal {}

class A<T> {
    T t;
    void set(T t) {
        this.t = t;
    }

    T get() {
        return t;
    }
}

public class Test {
    public static <T> void print1(A<? extends Animal> obj) {
        obj.set(new Dog()); //Line 22
        System.out.println(obj.get().getClass());
    }

    public static <T> void print2(A<? super Dog> obj) {
        obj.set(new Dog()); //Line 27
        System.out.println(obj.get().getClass());
    }

    public static void main(String[] args) {
        A<Dog> obj = new A<>();
        print1(obj); //Line 33
        print2(obj); //Line 34
    }
}

Line 22 does not compile because the compiler "s not sure about the data that would come at runtime". If I have understood right how generics work on line 22 we could pass : A <Animal>, A <Dog> and A <Cat>.

In short words Animal class or any other class that extents Animal.

Now if we look at print2 (public static <T> void print2(A<? super Dog> obj)) we have super, and this means that we can pass Animal or any superclass of Animal.

Now if the first method does not compile because the compiler does not know what type will be passed at runtime should this also be the case for the second method where super is used. For the second method, we can pass A<Animal> and A<Object>.

What I am missing here?

Thanks

Adrian
  • 680
  • 9
  • 17
  • Does this answer your question? [Difference between super T> and extends T> in Java](https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java) – LoolKovsky Jul 11 '20 at 09:07
  • 2
    _"If I have understood right how generics work on line 22 we could pass : `A `, `A ` and `A `."_ => No, this is not what generics tell you here. A variable `A extends Animal> obj` is of a parameterized type that could be initialized with a `A`, or `A`, or `A`, or whatever type that is a a subtype of `Animal`. Because it could be a `A` the compiler cannot allow the statement `obj.set(new Dog())`. – Seelenvirtuose Jul 11 '20 at 09:18
  • @Seelenvirtuose I have read the recommendation and still not very clear. I see that extends allows you to produce and super to consume. But here class A has a template parameter of type T. There you can pass any object type, why does it care about the parameter type? If I will instantiate class A, i could say A d = new A<>(); or A a = new A<>(); – Adrian Jul 11 '20 at 14:29
  • Java generics are not templates. – Mark Rotteveel Jul 11 '20 at 15:45
  • It is not a matter of what you can pass into a method! It is simply a type hierarchy! The type `A extends Animal>` is the supertype of `A` or `A`. Nothing else. But as the `? extends Animal` could be anything (that extends `Animal`, of course), you simply can'r call the setter. – Seelenvirtuose Jul 12 '20 at 08:23
  • @Seelenvirtuose please correct me if I am wrong. Type for A extends Animal> will be resolved at runtime. And because of this I could end with an object of type cat (obj from print1 function) and for this object I can try to set an instance of type dog (line 22 for the same function) – Adrian Jul 12 '20 at 17:08
  • 1
    Generics are fully _resolved_ at compile time. We also have _type erasure_, so the real type information is lost at runtime! Consider the following variable initialization: `A extends Animal> someVariable = new A()`. This is perfectly valid because `A< ? extends Animal>` is a supertype of `A`. But maybe you can see now, why `someVariable.set(new Dog())` cannot be allowed! – Seelenvirtuose Jul 12 '20 at 17:23
  • Thanks @Seelenvirtuose. Finally some light. Thanks for your time. – Adrian Jul 12 '20 at 18:10

0 Answers0