Generic return type upper bound - interface vs. class - surprisingly valid code

CharSequence is an interface. Therefore even if SomeClass does not implement CharSequence it would be perfectly possible to create a class

class SubClass extends SomeClass implements CharSequence

Therefore you can write

SomeClass c = getCharSequence();

because the inferred type X is the intersection type SomeClass & CharSequence.

This is a bit odd in the case of Integer because Integer is final, but final doesn't play any role in these rules. For example you can write

<T extends Integer & CharSequence>

On the other hand, String is not an interface, so it would be impossible to extend SomeClass to get a subtype of String, because java does not support multiple-inheritance for classes.

With the List example, you need to remember that generics are neither covariant nor contravariant. This means that if X is a subtype of Y, List<X> is neither a subtype nor a supertype of List<Y>. Since Integer does not implement CharSequence, you cannot use List<Integer> in your doCharSequence method.

You can, however get this to compile

<T extends Integer & CharSequence> void foo(List<T> list) {
    doCharSequence(list);
}  

If you have a method that returns a List<T> like this:

static <T extends CharSequence> List<T> foo() 

you can do

List<? extends Integer> list = foo();

Again, this is because the inferred type is Integer & CharSequence and this is a subtype of Integer.

Intersection types occur implicitly when you specify multiple bounds (e.g. <T extends SomeClass & CharSequence>).

For further information, here is the part of the JLS where it explains how type bounds work. You can include multiple interfaces, e.g.

<T extends String & CharSequence & List & Comparator>

but only the first bound may be a non-interface.


The type that is inferred by your compiler prior to the assignment for X is Integer & CharSequence. This type feels weird, because Integer is final, but it's a perfectly valid type in Java. It is then cast to Integer, which is perfectly OK.

There is exactly one possible value for the Integer & CharSequence type: null. With the following implementation:

<X extends CharSequence> X getCharSequence() {
    return null;
}

The following assignment will work:

Integer x = getCharSequence();

Because of this possible value, there's no reason why the assignment should be wrong, even if it is obviously useless. A warning would be useful.

The real problem is the API, not the call site

In fact, I've recently blogged about this API design anti pattern. You should (almost) never design a generic method to return arbitrary types because you can (almost) never guarantee that the inferred type will be delivered. An exception are methods like Collections.emptyList(), in case of which the emptiness of the list (and generic type erasure) is the reason why any inference for <T> will work:

public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}