Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics lower bound

Tags:

java

generics

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.

like image 906
zexed640 Avatar asked Dec 10 '25 07:12

zexed640


2 Answers

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 with StringBuilder. It just wants T.
  • Base has a common super with StringBuilder in Object.
like image 105
Sree Kumar Avatar answered Dec 11 '25 21:12

Sree Kumar


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());
like image 33
markspace Avatar answered Dec 11 '25 21:12

markspace



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!