Search This Blog

Tuesday, October 19, 2010

Lower and Upper Generics

Every one that been using Java for some time have run into generics. Having worked on building a JVM for seven years I thought that I knew all about them. I guess I could blame the fact on that almost all type information is erased by the time the byte code comes to the JVM.

So the other day I got a question from a colleague at work about a syntax. He is working on a new API and would like to make use of generics. He drew three different declarations

public Bus getBus();

public Bus<? extends T> getBus();

public Bus <? super T> getBus();

I scratched my head and said I defiantly knew about the first two. First is the Exact Bound, meaning T and only T, no super type of T (Object) or derived version of T (T'). Will be returned by the getBus() property.

Second option, ? extends T, meaning T and all it's derivatives (T', T'') etc. But not Object or any super type of T. What normally is declared as Upper Bound. All types that implements or extends T qualify as type argument.

The third one, I'd never seen before. The third one didn't make any sense. I asked him if it compiled and he answered back that it did.
Logically the syntax would imply that anything that T is derived of would be allowed to be returned by the method. Reasonably this syntax must be called Lower Bound as the covariant version of Bus is normally called Upper Bound.

The other interesting part of the syntax is that it only seems to apply to the initialization of a variable/field/return i.e. a reference. As soon as the reference is used the Upper Bound rules apply. Example take the following hierarchy:

public static class Super

{

}


public static class Foo extends Super

{

}


public static class Bar extends Foo

{

}


Then the following does not compile

List <? super T> Foo list = new ArrayList();


list.add(new Super()); // error


list.add(new Object()); // error


Which the syntax List<? super Foo> list seems to imply. That, whatever is being assigned to list needs to be instantiated with a super type of T (in the example Foo). So it cannot be assigned an ArrayList of Bar for example.

list = new ArrayList<Bar>();


Does not compile! When using a Lower bound generics however like the supplied type must be of the same type or derivative of the type.

No comments: