简体   繁体   中英

Java generics lower bound

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.

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());

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()) 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM