I understand upper bound clearly, but don't fully understand lower bound. As for example I have this code:
public class Main<T> {
private T t;
public Main(T t) {
this.t = t;
}
private static class Base {}
public static void main(String[] args) {
Main<? super Base> main = new Main<>(new StringBuilder());
System.out.println(main.t.getClass());
}
}
Why there is no error during compile despite of StringBuilder
isn't super class of Base
. As I thought it would be illegal to provide type which is irrelevant (I know that it's impossible to assign non child class to t
after type inference). Also it works with collections, does it means that collection could possibly store no child, no super class of Base
? Please do not link me to PECS questions, I have read them a lot.
CodePudding user response:
Edit: I saw it a little late that @markspace's answer is nearly the same and was posted before this. I am only retaining this here due different styles of explanation, that is all.
This should be due to the diamond operator <>
due to which automatic inference happens based on the most possible route, in this case the constructor parameter.
I could not locate the official description of the diamond operator, but various sources describe it to the effect - the Java compiler does a type inference when given the diamond operator feature determines the most suitable constructor declaration that matches the invocation.
If you change your declaration to GenericsSuper<? super Base> main = new GenericsSuper<StringBuilder>(new StringBuilder())
you will get your expected error.
Without this explicit declaration, <>
leads to <Object>
due to the super
restriction, and consequently anything is allowed, because:
- The code in
GenericsSuper
has no problem withStringBuilder
. It just wantsT
. Base
has a common super withStringBuilder
inObject
.
CodePudding user response:
I'm going to add this as an actual answer.
I think <T>
here is Object, which is a legal super type of both Base and StringBuilder. The way you are doing this / thinking about this is flawed, basically. Check out the answer to this question (ignore the duplicate text for PECS):
Difference between <? super T> and <? extends T> in Java
Notice the examples that the accepted answer gives, especially the one with <Object>
:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Since you're allowing the diamond operator to "figure out" the type of T
, it "figures out" that Object
works and uses that. Untested, but check if this also compiles:
Main<? super Base> main = new Main<Object>(new StringBuilder());