JavaRanch Home    
 
This page:         last edited 22 March 2010         What's Changed?         Edit

Generics Super And Extends   

Let's consider a small example on Generics:


     List<? super String> st;
     st.add(new Object()); // This gives a compile time error.

In the above example, "st" is a reference variable and and it's reference type is List<? super String>. What does it mean? Yes, it says "ANY super class of String". But keep in mind that it is not saying that you can pass any super type of String to the add(-) method of st. The only thing what it is saying is that the VALUE object for this variable (initialization value) CAN be either String or a super-type of it. Let's see a simple example.

Given the statement below:


        List<? super String> st;  

According to the generic declaration shown above, you can INSTANTIATE the variable st, with any super type of String, as the generic-argument. For an example:


     st=new ArrayList<String>();  
     st=new ArrayList<Object>();  
     st=new ArrayList<Serializable>();  // String implements Serializable  

All of the above instantiations are correct, because java.lang.Object and java.io.Serializable are super types of String, (and String is the same type, so it also can be used).

Now the question is, what can you pass to the add(-) method? Think about it. The compiler don't know, what will be the instantiation generic type (right side) at the compile time. It can be either String, Object, or Serializable, .... as I shown above.

The key point you have to keep in mind again and again, is, the COMPILER don't know about the INSTANTIATION generic type exactly. The compiler know that it can be ANY super class of String. But it does not know what it is exactly. Because the Java compilation process always deals with the reference type only. (Think about it. You can specify so many instantiations for a one reference variable within a loop, or in a nested if condition. Thus the COMPILER cannot track them).

The argument you passed to the st.add(-) method, MUST be same or a super class of the INSTANTIATION generic type. But as I described above, the compiler doesn't know, about the INSTANTIATION Generic type exactly. It knows about the reference generic type only (i.e. List<? super String>).

Now, if you attempt to pass an "Object" instance to the add(-) method, the compiler will not permit you to do so. Because as I said, the compiler doesn't know about the instantiation generic type, and the compiler knows that passing an "Object" instance MAY BE a problem at runtime if the instantiation generic-type is NOT Object. In another way, the compiler knows that passing a java.io.Serializable (implemented) instance MAY BE a problem at runtime if the instantiation generic-type is NOT either Serializable or a super-type of it. In these cases, the compiler gives an error, as I shown in the first code.

But, what if we are passing a "String" instance to the add(-) method? In this case, the compiler know that it is IMPOSSIBLE TO BE a problem at runtime, even if the instantiation generic type is either String, Object, or Serializable. Because Object and Serializable are super types of String. In this case, it will compile successfully.

Also, imagine that SubString? is a sub class of String (even though it is not possible to extend from String, as String is a final class), In this case you can pass a SubString? instance to the add(-) method, by applying the above theory.

Now, as a summary, we can say, if the generic type of the REFERENCE is List<? super X>, we can pass either X or any SUB class of the X to the add(-) method. But you can NOT pass a SUPER class of X.

Can you try to apply the above theory, when the REFERENCE generic type is List<? extends Number>


JavaRanchContact us — Copyright © 1998-2014 Paul Wheaton