Generic upper bounded wildcard instantiation known at run time
Asked Answered
B

1

0
class Aliphatic<F> extends Organic<F>{}
class Hexane<G> extends Aliphatic<G>{}
public class Organic<E>{
    void react(E e){}
    static void main(String[] args){
        Organic<? extends Organic> compound = new Aliphatic<Organic>();
        compound.react(new Organic());
    }
}

Why can't I call react method with Organic argument? The generic type ot the reference <? extends Organic> says that the generic type of the instantiation canb either a Organic, or a subtype of Organic.

Is because the compiler doesn't know this instantiation generic type until runtime type an so, it does not bind any value to its generic criteria?

Why is this case working? Is this case the same?

public class WildcardCollection {
    public static void main (String[] args){
        WildcardCollection w = new WildcardCollection();
        w.myMethod(new Items("hola",1));     //Compile
        w.myMethod(new SubItems("nuevo",3)); //Compile
    }
    public <T extends Items> void myMethod(T a){ //Same as above
        System.out.println("hi: "+a);
    }
}
class SubItems extends Items {
    SubItems(){};
    SubItems(String s, int i){ super(s,i);}
}
class Items implements Comparable<Items> {
    private String name;
    private int value;

    public Items() {}

    public Items(String n, int i){ this.name = n; this.value = i;}
    public String getName(){ return this.name;}
    public int getValue(){ return this.value;}

    public String toString(){ return "(" + this.name + "-" + this.value + ")";}

    public int compareTo(Items i){
        return this.value - i.getValue();
    }
}
Brigandine answered 15/10, 2012 at 14:54 Comment(2)
related: https://mcmap.net/q/236174/-explanation-of-the-get-put-principleDeformed
And another plug for angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html - I've never found a question I had about generics that can't be answered by reference to that site.Applaud
A
2

Quite simply, if you have an object of some generic type with a type parameter T instantiated with a ? extends X wildcard then you can't call methods on the object that take parameters of type T because the compiler can't guarantee type safety. However you can call methods that return T (and assign the return value to a variable of type X). In your specific example it looks like this should be safe

Organic<? extends Organic> compound = new Aliphatic<Organic>();
compound.react(new Organic());

but remember that the compiler has to match the react call based on the declaration type (? extends Organic), it can't rely on what you've assigned on the RHS. If the compiler allowed this then it would also have to allow

Organic<? extends Organic> compound = new Aliphatic<Hexane<?>>();
compound.react(new Organic());

which is clearly not correct - it's exactly the same situation as

Collection<? extends Number> nums = new ArrayList<Float>();
nums.add(Integer.valueOf(1));

(all this is aside from the fact that since Organic is generic you need to say Organic<? extends Organic<?>> or similar rather than just Organic<? extends Organic>)

Applaud answered 15/10, 2012 at 15:39 Comment(4)
So it is useless to allow to declare a reference Organic<? extends Organic> if you can not add anything but null. ¿?Brigandine
If you want to be able to "add" anything (i.e. pass in parameters of the variable type) then the compiler needs to be able to work out that the types are compatible, so you need a concrete type. Organic<Organic> compound = new Aliphatic<Organic>(); would be fine.Applaud
Why is this case working in WildcardCollection? Is this case the same?Brigandine
No, your WildcardCollection example is different because it doesn't use any wildcards or parameterized types. Generic methods like myMethod are a different thing from generic types.Applaud

© 2022 - 2024 — McMap. All rights reserved.