Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 545
John Assymptoth Avatar asked Jan 23 '11 17:01

John Assymptoth


People also ask

Can you put variables in an array Java?

A Java Array is a collection of variables of the same type. For instance, an array of int is a collection of variables of the type int . The variables in the array are ordered and each have an index.

What is the use of wildcard in Java?

The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.

Which wildcard can be used if a variable can be accessed using object class method?

Unbounded wildcard − If a variable can be accessed using Object class method then use an unbound wildcard.

What is a wildcard parameterized type?

In the Java programming language, the wildcard ? is a special kind of type argument that controls the type safety of the use of generic (parameterized) types. It can be used in variable declarations and instantiations as well as in method definitions, but not in the definition of a generic type.


2 Answers

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.

like image 158
Favonius Avatar answered Sep 28 '22 13:09

Favonius


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.

like image 22
biziclop Avatar answered Sep 28 '22 12:09

biziclop