Question

In Java, why can't an array be a Type Variable's bound, but can be a Wildcard's bound?

You can have:

List< ? extends Integer[] > l;

but you can't have:

class MyClass< T extends Integer[] > { } // ERROR!

Why?

Was it helpful?

Solution

Consider this Java code:

package test;

public class Genric<E>
{
    public Genric(E c){
        System.out.println(c.getClass().getName());
    }   
    public static void main(String[] args) {
        new Genric<Integer[]>(new Integer[]{1,2});
    }
}

For your first case:

List< ? extends Integer[] > l;

When you do something like this List< ? extends Integer[] > l; then the Java compiler sees it as a List< ? extends Object> l; and translates it accordingly. So this is why you don't get any error.

The generated byte-code is as follows:

   .
   .
   .
   20:  aastore
   21:  invokespecial   #52; //Method "<init>":(Ljava/lang/Object;)V
   24:  return
   .
   .

Checkout the line number 21. Although, I have passed an array of java.lang.Integer; internally it is translated to java.lang.Object.

For your second case:

class MyClass< T extends Integer[] > { } // ERROR!

As per java language specification:

TypeParameter:
TypeVariable TypeBoundopt

TypeBound:
extends ClassOrInterfaceType AdditionalBoundListopt
.
.

As you can see the the bound consists solely of class or an interface (not even primitive types). So when you do something like this class MyClass< T extends Integer[] > { } then Integer[] does not qualify as a class or interface.

As per my understanding of Java Spec, this was done to solve all the scenarios like

  1. class MyClass< T extends Integer[] >
  2. class MyClass< T extends Integer[][] >
  3. ..
  4. class MyClass< T extends Integer[][]...[] >

Because all of them can be represented as java.lang.Object and when passed as parameter, as in example

public Genric(E c){
            System.out.println(c.getClass().getName());
        }

as 'c' remembers its true type.

Hope this will help.

OTHER TIPS

I'm trying to think about specific reasons this should be forbidden but the only one I can think of is that it's a completely unnecessary construct, because:

class Foo<T extends Integer[]> {
   T bar();
}

is equivalent to

class Foo<T extends Integer> {
   T[] bar();
}

Obviously the same cannot be said about the wildcard case, hence it's allowed there.

You can do something like:

public class MyClass<K> {
    K array;
    public MyClass(K k) {
       array = k;
    }

Or you could do something like this:

class MyClass< T extends Integer > {
   ...make your variable MyClass[]...
}

Hope this helps and I'm not too far off what you were asking for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top