Angelika Langer - Training & Consulting
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | CONTACT | Twitter | Lanyrd | Linkedin
Books  
HOME 

GENERICS
  FAQ    
    CONTENT
    FUNDAMENTALS
    FEATURES
    PRACTICAL
    TECHNICAL
    INFORMATION
    GLOSSARY
    INDEX
    PDF VERSION
 
LAMBDAS 
IOSTREAMS 
ABOUT 
CONTACT 
Java Generics FAQs - Generic And Parameterized Types

This is a collection of answers to frequently asked questions (FAQs) about Java Generics, a new language feature added to the Java programming language in version 5.0 of the Java Standard Edition (J2SE 5.0).

If you want to provide feedback or have any questions regarding Java generics, to which you cannot find an answer in this document, feel free to send me EMAIL or use the GENERICS FAQ form.
A printable version of the FAQ documents is available in PDF format (4.5MB).

Java Generics FAQs - Generic And Parameterized Types

Generic And Parameterized Types

© Copyright 2004-2022 by Angelika Langer.  All Rights Reserved.
Fundamentals Concrete Instantiations Raw Types


Wildcard Instantiations

Generic And Parameterized Types


 

Fundamentals

What is a parameterized or generic type?
 
A generic type is a type with formal type parameters. A parameterized type is an instantiation of a generic type with actual type arguments.
A generic type is a reference type that has one or more type parameters. These type parameters are later replaced by type arguments when the generic type is instantiated (or declared ). 

Example (of a generic type): 

interface Collection<E>  { 
  public void add (E x); 
  public Iterator<E> iterator();
}
The interface Collection has one type parameter E .  The type parameter E is a place holder that will later be replaced by a type argument when the generic type is instantiated and used. The instantiation of a generic type with actual type arguments is called a parameterized type

Example (of a parameterized type): 

Collection<String> coll = new LinkedList<String>();
The declaration Collection<String> denotes a parameterized type, which is an instantiation of the generic type Collection ,  where the place holder E has been replaced by the concrete type String .
LINK TO THIS GenericTypes.FAQ001
REFERENCES What is a type parameter?

How do I define a generic type?
 
Like a regular type, but with a type parameter declaration attached.
A generic type is a reference type that has one or more type parameters. In the definition of the generic type, the type parameter section follows the type name. It is a comma separated list of identifiers and is delimited by angle brackets. 

Example (of a generic type): 

class Pair<X,Y>  { 
  private X first;
  private Y second;

  public Pair(X a1, Y a2) {
    first  = a1;
    second = a2;
  }
  public X getFirst()  { return first; }
  public Y getSecond() { return second; }
  public void setFirst(X arg)  { first = arg; }
  public void setSecond(Y arg) { second = arg; }
}

The class Pair has two type parameters X and Y .  They are replaced by type arguments when the generic type Pair is instantiated. For instance, in the declaration Pair<String, Date> the type parameter X is replaced by the type argument String and Y is replaced by  Date
The scope of the identifiers X and Y is the entire definition of the class.  In this scope the two type parameters X and Y are used like they were types (with some restrictions). In the example above, the type parameters are used as the argument and return type of instance methods and the types of instance fields. 
Type parameters can be declared with bounds. Bounds give access to methods of the unknown type that the type parameter stands for. In our example, we do not invoke any methods of the unknown types X and Y . For this reason, the two type parameters are unbounded.
LINK TO THIS GenericTypes.FAQ002
REFERENCES What is a type parameter?
What is a bounded type parameter?
What is a type parameter bound?

Are there any types that cannot have type parameters?

All types, except enum types, anonymous inner classes and exception classes, can be generic..
Almost all reference types can be generic.  This includes classes, interfaces, nested (static) classes, nested interfaces, inner (non-static) classes, and local classes. 

The following types cannot be generic: 

Anonymous inner classes . They can implement a parameterized interface or extend a parameterized class, but they cannot themselves be generic classes.  A generic anonymous class would be nonsensical.  Anonymous classes do not have a name, but the name of a generic class is needed for declaring an instantiation of the class and providing the type arguments.  Hence, generic anonymous classes would be pointless. 

Exception types .  A generic class must not directly or indirectly be derived from class Throwable .  Generic exception or error types are disallowed because the exception handling mechanism is a runtime mechanism and the Java virtual machine does not know anything about Java generics.  The JVM would not be capable of distinguishing between different instantiations of a generic exception type. Hence, generic exception types would be pointless. 

Enum types . Enum types cannot have type parameters.  Conceptually, an enum type and its enum values are static.  Since type parameters cannot be used in any static context, the parameterization of an enum type would be pointless.

LINK TO THIS GenericTypes.FAQ003
REFERENCES Can I use generic / parameterized types in exception handling?
Why are generic exception and error types illegal?
Why are generic enum types illegal?

How is a generic type instantiated?

By providing a type argument per type parameter. 
In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type. 

Example (of a generic type): 

    class Pair<X,Y>  { 
      private X first;
      private Y second;

      public Pair(X a1, Y a2) {
        first  = a1;
        second = a2;
      }
      public X getFirst()  { return first; }
      public Y getSecond() { return second; }
      public void setFirst(X arg)  { first = arg; }
      public void setSecond(Y arg) { second = arg; }
    }

If we want to use the generic type Pair we must specify the type arguments that shall replace the place holders X and Y .  A type argument can be a concrete reference type, such as String , Long , Date , etc. 

Example (of a concrete parameterized type): 

public void printPair( Pair<String,Long> pair) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
}

Pair<String,Long> limit = new Pair<String,Long> ("maximum",1024L);
printPair(limit);

The instantiation Pair<String,Long> is a concrete parameterized type and it can be used like a regular reference type (with a couple of restrictions that are discussed later).  In the example, we have been using the concrete parameterized type as argument type of a method, as type of a reference variable, and in a new expression for creation of an object. 

In addition to concrete instantiation there so-called wildcard instantiations .  They do not have concrete types as type arguments, but so-called wildcards . A wildcard is a syntactic construct with a " ? " that denotes not just one type, but a family of types.  In its simplest form a wildcard is just a question mark and stands for "all types". 

Example (of a wildcard parameterized type): 

public void printPair( Pair<?,?> pair) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
}

Pair<?,?> limit = new Pair<String,Long> ("maximum",1024L);
printPair(limit);

The declaration Pair<?,?> is an example of a wildcard parameterized type, where both type arguments are wildcards. Each question mark stands for a separate representative from the family of "all types".  The resulting family of instantiations comprises all instantiations of the generic type Pair .  (Note: the concrete type arguments of the family members need not be identical; each " ? " stands for a separate type.) A reference variable or method parameter whose type is a wildcard parameterized type, such as limit and pair in the example, can refer to any member of the family of types that the wildcard denotes. 

It is permitted to leave out the type arguments altogether and not specify type arguments at all. A generictype without type arguments is called raw type and is only allowed for reasons of compatibility with non-generic Java code.  Use of raw types is discouraged.  The Java Language Specification even states that it is possible that future versions of the Java programming language will disallow the use of raw types.

LINK TO THIS GenericTypes.FAQ004
REFERENCES What is a type argument?
Which types are permitted as type arguments?
What is a wildcard?
What is a concrete parameterized type?
What is a wildcard parameterized type?
Can I use a concrete parameterized type like any other type?
Can I use a wildcard parameterized like any other type?
What is the raw type?

Why do instantiations of a generic type share the same runtime type?

Because of type erasure.
The compiler translates generic and parameterized types by a technique called type erasure .  Basically, it elides all information related to type parameters and type arguments. For instance, the parameterized type List<String> is translated to type List , which is the so-called raw type .  The same happens for the parameterized type List<Long> ; it also appears as List in the bytecode. 

After translation by type erasure, all information regarding type parameters and type arguments has disappeared. As a result, all instantiations of the same generic type share the same runtime type, namely the raw type. 

Example (printing the runtime type of two parameterized types): 

System.out.println("runtime type of ArrayList<String>: "+ne w ArrayList<String>().getClass());
System.out.println("runtime type of ArrayList<Long>  : "+new ArrayList<Long>().g etClass());


prints:   runtime type of ArrayList<String> : class java.util. ArrayList
      runtime type of ArrayList<Long>   : class java.util. ArrayList
The example illustrates that ArrayList<String> and ArrayList<Long> share the runtime type ArrayList
LINK TO THIS GenericTypes.FAQ005
REFERENCES How does the compiler translate Java generics?
What is type erasure?
What is the raw type?

Can I cast to a parameterized type?

Yes, you can, but under certain circumstances it is not type-safe and the compiler issues an "unchecked" warning.
All instantiations of a generic type share the same runtime type representation, namely the representation of the raw type. For instance, the instantiations of a generic type List ,  such as List<Date> , List<String> , List<Long> , etc. have different static types at compile time, but the same dynamic type List at runtime. 

A cast consists of two parts: 

  • a static type check performed by the compiler at compile time and 
  • a dynamic type check performed by the virtual machine at runtime. 
The static part sorts out nonsensical casts, that cannot succeed, such as the cast from String to Date or from List<String> to List<Date>

The dynamic part uses the runtime type information and performs a type check at runtime.  It raises a ClassCastException if the dynamic type of the object is not the target type (or a subtype of the target type) of the cast. Examples of casts with a dynamic part are the cast from Object to String or from Object to List<String> .  These are the so-called downcasts, from a supertype down to a subtype. 

Not all casts have a dynamic part. Some casts are just static casts and require no type check at runtime.  Examples are the casts between primitive types, such as the cast from long to int or byte to char .  Another example of static casts are the so-called upcasts, from a subtype up to a supertype, such as the casts from String to Object or from LinkedList<String> to List<String> . Upcasts are casts that are permitted, but not required.  They are automatic conversions that the compiler performs implicitly, even without an explicit cast expression in the source code, which means, the cast is not required and usually omitted.  However, if an upcast appears somewhere in the source code then it is a purely static cast that does not have a dynamic part. 

Type casts with a dynamic part are potentially unsafe, when the target type of the cast is a parameterized type.  The runtime type information of a parameterized type is non-exact, because all instantiations of the same generic type share the same runtime type representation. The virtual machine cannot distinguish between different instantiations of the same generic type.  Under these circumstances the dynamic part of a cast can succeed although it should not. 

Example (of unchecked cast): 

void m1() {
  List<Date> list = new ArrayList<Date>();
  ...
  m2(list);
}
void m2(Object arg) {
  ...
  List<String> list = (List<String>) arg;    // unchecked warning
  ...
  m3(list);
  ...
}
void m3(List<String> list) {
  ...
  String s = list.get(0);      // ClassCastException
  ...
}
The cast from Object to List<String> in method m2 looks like a cast to List<String> , but actually is a cast from Object to the raw type List . It would succeed even if the object referred to were a List<Date>   instead of a List<String>

After this successful cast we have a reference variable of type List<String> which refers to an object of type List<Date> . When we retrieve elements from that list we would expect String s, but in fact we receive Date s - and a ClassCastException will occur in a place where nobody had expected it. 

We are prepared to cope with ClassCastException s when there is a cast expression in the source code, but we do not expect ClassCastException s when we extract an element from a list of strings.  This sort of unexpected ClassCastException is considered a violation of the type-safety principle.  In order to draw attention to the potentially unsafe cast the compiler issues an "unchecked" warning when it translates the dubious cast expression. 

As a result, the compiler emits "unchecked" warnings for every dynamic cast whose target type is a parameterized type.  Note that an upcast whose target type is a parameterized type does not lead to an "unchecked" warning, because the upcast has no dynamic part. 

LINK TO THIS GenericTypes.FAQ006
REFERENCES Why do instantiations of the same generic type share the same runtime type?
What does type-safety mean?
What is the type erasure of a parameterized type?

Can I use parameterized types in exception handling?

No.  Exception and error types must not be generic.
It is illegal to define generic type that are directly or indirectly derived from class Throwable . Consequently, no parameterized types appear anywhere in exception handling.
LINK TO THIS GenericTypes.FAQ007
REFERENCES Why are generic exception and error types illegal?

Can generic types have static members?

Yes.
Generic types can have static members, including static fields, static methods and static nested types. Each of these static members exists once per enclosing type, that is, independently of the number of objects of the enclosing type and regardless of the number of instantiations of the generic type  that may be used somewhere in the program. The name of the static member consists - as is usual for static members - of the scope (packages and enclosing type) and the member's name. If the enclosing type is generic, then the type in the scope qualification must be the raw type, not a parameterized type.
LINK TO THIS GenericTypes.FAQ008
REFERENCES How do I refer to static members of a generic or parameterized type?
How do I refer to a (non-static) inner class of a generic or parameterized type?
How do I refer to an interface type nested into a generic or parameterized type?
How do I refer to an enum type nested into a generic or parameterized type?
Can I import a particular parameterized type?

Concrete Instantiations

What is a concrete parameterized type?

An instantiation of a generic type where all type arguments are concrete types rather than wildcards.
Examples of concrete parameterized types are List<String> , Map<String,Date> , but not List<? extends Number> or Map<String,?> .
LINK TO THIS GenericTypes.FAQ101
REFERENCES What is a wildcard?
What is a wildcard parameterized type?

Is List<Object> a supertype of List<String>?

No, different instantiations of the same generic type for different concrete type arguments have no type relationship.
It is sometimes expected that a List<Object> would be a supertype of a List<String> , because Object is a supertype of String .  This expectation stems from the fact that such a type relationship exists for arrays:  Object[] is a supertype of String[] , because Object is a supertype of String . (This type relationship is known as covariance .)  The super-subtype-relationship of the component types extends into the corresponding array types. No such a type relationship exists for instantiations of generic types. (Parameterized types are not covariant.) 

The lack of a super-subtype-relationship among instantiations of the same generic type has various consequences.  Here is an example. 

Example: 

void printAll(ArrayList<Object> c) {
  for (Object o : c) 
    System.out.println(o);
}

ArrayList<String> list = new ArrayList<String>();
... fill list ...
printAll(list);   // error

A ArrayList<String> object cannot be passed as argument to a method that asks for a ArrayList<Object> because the two types are instantiations of the same generic type, but for different type arguments, and for this reason they are not compatible with each other. 

On the other hand, instantiations of different generic types for the same type argument can be compatible. 

Example: 

void printAll(Collection<Object> c) {
  for (Object o : c) 
    System.out.println(o);
}

List<Object> list = new ArrayList<Object>();
... fill list ...
printAll(list);   // fine

A List<Object> is compatible to a Collection<Object> because the two types are instantiations of a generic supertype and its generic subtype and the instantiations are for the same type argument Object

Compatibility between instantiations of the same generic type exist only among wildcard instantiations and concrete instantiations that belong to the family of instantiations that the wildcard instantiation denotes.

LINK TO THIS GenericTypes.FAQ102
REFERENCES What is a concrete parameterized type?
What is a wildcard parameterized type?
How do parameterized types fit into the Java type system?
How does the raw type relate to instantiations of the corresponding generic type?
How do instantiations of a generic type relate to  instantiations of other generic types?
How do unbounded wildcard instantiations of a generic type relate to other instantiations of the same generic type?
How do wildcard instantiations with an upper bound relate to other instantiations of the same generic type?
How do wildcard instantiations with a lower bound relate to other instantiations of the same generic type?

Can I use a concrete parameterized type like any other type?

Almost.
Concrete parameterized types are concrete instantiations of a generic type.  They are almost like types; there are only a few restrictions.  They can NOT be used for the following purposes: 
  • for creation of arrays
  • in exception handling
  • in a class literal
  • in an instanceof expression
LINK TO THIS GenericTypes.FAQ103
REFERENCES Can I create an array whose component type is a concrete parameterized type?
Can I use parameterized types in exception handling?
Why is there no class literal for the concrete parameterized type?

Can I create an array whose component type is a concrete parameterized type?
 
No, because it is not type-safe.
Arrays are covariant, which means that an array of supertype references is a supertype of an array of subtype references.  That is, Object[] is a supertype of String[] and a string array can be accessed through a reference variable of type Object[]

Example (of covariant arrays): 

Object[] objArr = new String[10];  // fine
objArr[0] = new String();
In addition, arrays carry runtime type information about their component type, that is, about the type of the elements contained.  The runtime type information regarding the component type is used when elements are stored in an array in order to ensure that no "alien" elements can be inserted. 

Example (of array store check): 

Object[] objArr = new String[10];
objArr[0] = new Long(0L); // compiles; fails at runtime with ArrayStoreException
The reference variable of type Object[] refers to a String[] , which means that only strings are permitted as elements of the array.  When an element is inserted into the array, the information about the array's component type is used to perform a type check - the so-called array store check. In our example the array store check will fail because we are trying to add a Long to an array of String s.  Failure of the array store check is reported by means of a ArrayStoreException

Problems arise when an array holds elements whose type is a concrete parameterized type. Because of type erasure, parameterized types do not have exact runtime type information.  As a consequence, the array store check does not work because it uses the dynamic type information regarding the array's (non-exact) component type for the array store check. 

Example (of array store check in case of parameterized component type): 

Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10]; // illegal
Object[] objArr = intPairArr; 
objArr[0] = new Pair<String,String>("",""); // should fail, but would succeed
If arrays of concrete parameterized types were allowed, then a reference variable of type Object[] could refer to a Pair<Integer,Integer>[] , as shown in the example. At runtime an array store check must be performed when an array element is added to the array. Since we are trying to add a Pair<String,String> to a Pair<Integer,Integer>[] we would expect that the type check fails. However, the JVM cannot detect any type mismatch here: at runtime, after type erasure, objArr would have the dynamic type Pair[] and the element to be stored has the matching dynamic type Pair . Hence the store check succeeds, although it should not. 

If it were permitted to declare arrays that holds elements whose type is a concrete parameterized type we would end up in an unacceptable situation.  The array in our example would contain different types of pairs instead of pairs of the same type.  This is in contradiction to the expectation that arrays hold elements of the same type (or subtypes thereof).  This undesired situation would most likely  lead to program failure some time later, perhaps when a method is invoked on the array elements. 

Example (of subsequent failure): 

Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10]; // illegal
Object[] objArr = intPairArr; 
objArr[0] = new Pair<String,String>("",""); // should fail, but would succeed

Integer i = intPairArr[0].getFirst(); // fails at runtime with ClassCastException

The method getFirst is applied to the first element of the array and it returns a String instead of an Integer because the first element in the array intPairArr is a pair of strings, and not a pair of integers as one would expect. The innocent-looking assignment to the Integer variable i will fail with a ClassCastException , although no cast expression is present in the source code.  Such an unexpected ClassCastException is considered a violation of type-safety. 

In order to prevent programs that are not type-safe all arrays holding elements whose type is a concrete parameterized type are illegal. For the same reason, arrays holding elements whose type is a wildcard parameterized type are banned, too.  Only arrays with an unbounded wildcard parameterized type as the component type are permitted.  More generally, reifiable types are permitted as component type of arrays, while arrays with a non-reifiable component type are illegal.

LINK TO THIS GenericTypes.FAQ104
REFERENCES What does type-safety mean?
Can I declare a reference variable of an array type whose component type is a concrete parameterized type?
Can I create an array whose component type is a wildcard parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
What is a reifiable type?

Can I declare a reference variable of an array type whose component type is a concrete parameterized type?
 
Yes, you can, but you should not, because it is neither helpful nor type-safe.
You can declare a reference variable of an array type whose component type is a concrete parameterized type. Arrays of such a type must not be created.  Hence, this reference variable cannot refer to an array of its type.  All that it can refer to is null , an array whose component type is a non-parameterized subtype of the concrete parameterized type, or an array whose component type is the corresponding raw type. Neither of these cases is overly useful, yet they are permitted. 

Example (of an array reference variable with parameterized component type): 

Pair<String,String>[] arr = null;  // fine
arr = new Pair<String,String>[2] ; // error: generic array creation
The code snippet shows that a reference variable of type Pair<String,String>[] can be declared, but the creation of such an array is rejected.  But we can have the reference variable of type Pair<String,String>[] refer to an array of a non-parameterized subtype. 

Example (of another array reference variable with parameterized component type): 

class Name extends Pair<String,String> { ... }

Pair<String,String>[] arr = new Name[2] ;    // fine

Which raises the question: how useful is such an array variable if it never refers to an array of its type?  Let us consider an example. 

Example (of an array reference variable refering to array of subtypes; not recommended): 

void printArrayOfStringPairs( Pair<String,String>[] pa) {
  for (Pair<String,String> p : pa)
    if (p != null)
      System.out.println(p.getFirst()+" "+p.getSecond()); 
}
Pair<String,String>[] createArrayOfStringPairs() {
  Pair<String,String>[] arr = new Name[2];
  arr[0] = new Name("Angelika","Langer");   // fine
  arr[1] = new Pair<String,String>("a","b");  // fine (causes ArrayStoreException)
  return arr;
}
void extractStringPairsFromArray( Pair<String,String>[] arr) {
  Name name = (Name) arr[0]; // fine
  Pair<String,String> p1 = arr[1];    // fine
}
void test() {
  Pair<String,String>[] arr = createArrayOfStringPairs ();
  printArrayOfStringPairs (arr); 
  extractStringPairsFromArray(arr);
}
The example shows that a reference variable of type Pair<String,String>[] can refer to an array of type Name[] , where Name is a non-parameterized subtype of Pair<String,String> .  However, using a reference variable of type Pair<String,String>[] offers no advantage over using a variable of the actual type Name[] .  Quite the converse; it is an invitation for making mistakes. 

For instance, in the createArrayOfStringPairs method the compiler would permit code for insertion of elements of type Pair<String,String> into the array though the reference variable of type Pair<String,String>[] . Yet, at runtime, this insertion will always fail with an ArrayStoreException because we are trying to insert a Pair into a Name[] .  The same would happen if we tried to insert a raw type Pair into the array; it would compile with an "unchecked" warning and would fail at runtime with an ArrayStoreException .  If we used Name[] instead of Pair<String,String>[] the debatable insertions would not compile in the first place. 

Also, remember that a variable of type Pair<String,String>[] can never refer to an array that contains elements of type Pair<String,String> .  When we want to recover the actual type of the array elements, which is the subtype Name in our example, we must cast down from Pair<String,String> to Name , as is demonstrated in the extractStringPairsFromArray method.  Here again, using a variable of type Name[] would be much clearer. 

Example (improved): 

void printArrayOfStringPairs( Pair<String,String>[] pa) {
  for (Pair<String,String> p : pa)
    if (p != null)
      System.out.println(p.getFirst()+" "+p.getSecond()); 
}
Name[] createArrayOfStringPairs() {
  Name[] arr = new Name[2] ;
  arr[0] = new Name("Angelika","Langer");   // fine
  arr[1] = new Pair<String,String>("a","b");  // error
  return arr;
}
void extractStringPairsFromArray( Name[] arr) {
  Name name = arr[0];               // fine (needs no cast)
  Pair<String,String> p1 = arr[1];    // fine
}
void test() {
  Name[] arr = createArrayOfStringPairs ();
  printArrayOfStringPairs (arr);
  extractStringPairsFromArray(arr);
}
Since an array reference variable whose component type is a concrete parameterized type can never refer to an array of its type, such a reference variable does not really make sense.  Matters are even worse than in the example discussed above, when we try to have the variable refer to an array of the raw type instead of a subtype. First, it leads to numerous "unchecked" warnings because we are mixing use of raw and parameterized type.  Secondly, and more importantly, this approach is not type-safe and suffers from all the deficiencies that lead to the ban of arrays of concrete instantiation in the first place. 

No matter how you put it, you should better refrain from using array reference variable whose component type is a concrete parameterized type.  Note, that the same holds for array reference variable whose component type is a wildcard parameterized type. Only array reference variable whose component type is an unbounded wildcard parameterized type make sense. This is because an unbounded wildcard parameterized type is a reifiable type and arrays with a reifiable component type can be created;  the array reference variable can refer to an array of its type and the deficiencies discussed above simply do not exist for unbounded wildcard arrays. 
 

LINK TO THIS GenericTypes.FAQ104A
REFERENCES What does type-safety mean?
Can I create an array whose component type is a concrete parameterized type?
Can I declare a reference variable of an array type whose component type is a bounded wildcard parameterized type?
Can I create an array whose component type is a wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is an unbounded wildcard parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
What is a reifiable type?

How can I work around the restriction that there are no arrays whose component type is a concrete parameterized type?

You can use arrays of raw types, arrays of unbounded wildcard parameteriezd types, or collections of concrete parameteriezd types as a workaround.
Arrays holding elements whose type is a concrete parameterized type are illegal. 

Example (of illegal array type): 

static void test() {
  Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10] ; // error
  addElements(intPairArr); 
  Pair<Integer,Integer> pair = intPairArr[1];
  Integer i = pair.getFirst();
  pair.setSecond(i);
}
static void addElements( Object[] objArr) {
  objArr[0] = new Pair<Integer,Integer>(0,0);
  objArr[1] = new Pair<String,String>("","");      // should fail with ArrayStoreException
}
The compiler prohibits creation of arrays whose component type is a concrete parameterized type, like Pair<Integer,Integer> in our example.  We discussed in the preceding entry why is it reasonable that the compiler qualifies a Pair<Integer,Integer>[] as illegal.  The key problem is that compiler and runtime system must ensure that an array is a homogenous sequence of elements of the same type.  One of the type checks, namely the array-store-check performed by the virtual machine at runtime, fails to detect the offending insertion of an alien element. In the example the second insertion in the addElements method should fail, because were are adding a pair of strings to an array of integral values, but it does not fail as expected  The reasons were discussed in the preceding entry. 

If we cannot use arrays holding elements whose type is a concrete parameterized type, what do we use as a workaround? 

Let us consider 3 conceivable workarounds: 

  • array of raw type
  • array of unbounded wildcard parameterized type
  • collection instead of array

Raw types and unbounded wildcard parameterized type are permitted as component type of arrays.  Hence they would be alternatives. 

Example (of array of raw type): 

static void test() {
  Pair[] intPairArr = new Pair[10]
  addElements(intPairArr); 
  Pair<Integer,Integer> pair = intPairArr[1];  // unchecked warning
  Integer i = pair.getFirst();                   // fails with ClassClassException
  pair.setSecond(i);
}
static void addElements(Object[] objArr) {
  objArr[0] = new Pair<Integer,Integer>(0,0);
  objArr[1] = new Pair<String,String>("","");    // should fail, but succeeds
}
Use of the raw type, instead of a parameterized type, as the component type of an array, is permitted.  The downside is that we can stuff any type of pair into the raw type array.  There is no guarantee that a Pair[] is homogenous in the sense that it contains only pairs of the same type.  Instead the Pair[] can contain a mix of arbitrary pair types.

This has numerous side effects.  When elements are fetched from the Pair[] only raw type Pair references are received.  Using raw type Pair s leads to unchecked warnings invarious situations, for instance, when we try to access the pair member or, like in the example, when we assign the Pair to the more specific Pair<Integer,Integer> , that we really wanted to use. 

Let us see whether an array of an unbounded wildcard parameterized type would be a better choice. 

Example (of array of unbounded wildcard parameterized type): 

static void test() {
  Pair<?,?>[] intPairArr = new Pair<?,?>[10]
  addElements(intPairArr); 
  Pair<Integer,Integer> pair = intPairArr[1];  // error
  Integer i = pair.getFirst(); 
  pair.setSecond(i);
}
static void addElements(Object[] objArr) {
  objArr[0] = new Pair<Integer,Integer>(0,0);
  objArr[1] = new Pair<String,String>("","");    // should fail, but succeeds
}


error: incompatible types
found   : Pair<?,?>
required: Pair<java.lang.Integer,java.lang.Integer>
        Pair<Integer,Integer> pair = intPairArr[1]; 
                                               ^
A Pair<?,?>[] contains a mix of arbitrary pair types; it is not homogenous and semantically similar to the raw type array Pair[] .  When we retrieve elements from the array we receive references of type Pair<?,?> , instead of type Pair in the raw type case.  The key difference is that the compiler issues an error for the wildcard pair where it issues "unchecked" warnings for the raw type pair.  In our example, we cannot assign the the Pair<?,?> to the more specific Pair<Integer,Integer> , that we really wanted to use.  Also, various operations on the Pair<?,?> would be rejected as errors. 

As we can see, arrays of raw types and unbounded wildcard parameterized types are very different from the illegal arrays of a concrete parameterized type. An array of a concrete wildcard parameterized type would be a homogenous sequence of elements of the exact same type. In constrast, arrays of raw types and unbounded wildcard parameterized type are heterogenous sequences of elements of different types. The compiler cannot prevent that they contain different instantiations of the generic type. 

By using arrays of raw types or unbounded wildcard parameterized types we give away the static type checks that a homogenous sequence would come with.  As a result we must use explicit casts or we risk unexpected ClassCastException s.  In the case of the unbounded wildcard parameterized type we are additionally restricted in how we can use the array elements, because the compiler prevents certain operations on the unbounded wildcard parameterized type.  In essence, arrays of raw types and unbounded wildcard parameterized types are semantically very different from what we would express with an array of a concrete wildcard parameterized type.  For this reason they are not a good workaround and only acceptable when the superior efficiency of arrays (as compared to collections) is of paramount importance. 


While arrays of concrete parameterized types are illegal, collections of concrete parameterized types are permitted. 

Example (using collections): 

static void test() {
  ArrayList<Pair<Integer,Integer>> intPairArr = new ArrayList<Pair<Integer,Integer>>(10) ;
  addElements(intPairArr); 
  Pair<Integer,Integer> pair = intPairArr. get (1);
  Integer i = pair.getFirst();
  pair.setSecond(i);
}
static void addElements( List<?> objArr) {
  objArr. add (0,new Pair<Integer,Integer>(0,0)); // error
  objArr. add (1,new Pair<String,String>("","")); // error
}


error: cannot find symbol
symbol  : method add(int,Pair<java.lang.Integer,java.lang.Integer>)
location: interface java.util.List<capture of ?>
        objArr.add(0,new Pair<Integer,Integer>(0,0)); 
              ^
error: cannot find symbol
symbol  : method add(int,Pair<java.lang.String,java.lang.String>)
location: interface java.util.List<capture of ?>
        objArr.add(1,new Pair<String,String>("","")); 
              ^
A collection of a concrete parameterized type is a homogenous sequence of elements and the compiler prevents any attempt to add alien elements by means of static type checks.  To this regard it is semantically similar to the illegal array, but otherwise collections are very different from arrays. They have different operations; no index operator, but get and add methods.  They have different type relationships; arrays are covariant, while collections are not. They are not as efficient as arrays; they add overhead in terms of memory footprint and performance. By using collections of concrete parameterized types as a workaround for the illegal array type many things change in your implementation. 

The different type relationships, for instance, can be observed in the example above and it renders method addElements pointless.  Using arrays we declared the argument type of the addElements method as type Object[] so that the method would accept all types of arrays.  For the collections there is no such supertype as an Object[] .  Type Collection<?> , or type List<?> in our example, comes closest to what the Object[] is for arrays.  But wildcard instantiations of the collection types give only limited access to the collections' operations.  In our example, we cannot insert any elements into the collection of integer pairs through a reference of type List<?> .  A method like addElements does not make any sense any longer; we would need a method specifically for a collection of Pair<Integer,Integer> instead.  In essence, you must design your APIs differently, when you work with collections instead of arrays. 

The most compelling argument against collections is efficiency; arrays are without doubt more efficient.  The argument in favor of collections is type safety; the compiler performs all necessary type checks to ensure that the collection is a homogenous sequence. 
 

LINK TO THIS GenericTypes.FAQ105
REFERENCES What is a reifiable type?
What is an unbounded wildcard?
What is an unbounded wildcard parameterized type?
What is the raw type?
Can I create an array whose component type is a wildcard parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
What is the difference between the unbounded wildcard parameterized type and the raw type?

Why is there no class literal for concrete parameterized types?
 
Because parameterized type has no exact runtime type representation.
A class literal denotes a Class object that represents a given type. For instance, the class literal String.class denotes the Class object that represents the type String and is identical to the Class object that is returned when method getClass is invoked on a S tring object. A class literal can be used for runtime type checks and for reflection. 

Parameterized types lose their type arguments when they are translated to byte code during compilation in a process called type erasure . As a side effect of type erasure, all  instantiations of a generic type share the same runtime representation, namely that of the corresponding raw type .  In other words, parameterized types do not have type representation of their own. Consequently, there is no point in forming class literals such as List<String>.class , List<Long>.class and List<?>.class , since no such Class objects exist.  Only the raw type List has a Class object that represents its runtime type. It is referred to as List.class .

LINK TO THIS GenericTypes.FAQ106
REFERENCES What is type erasure?
What is the raw type?

 

Raw Types

What is the raw type?

The generic type without any type arguments.
The generic type without any type arguments, like Collection , is called raw type

The raw type is assignment compatible with all instantiations of the generic type.  Assignment of an instantiation of a generic type to the corresponding raw type is permitted without warnings; assignment of the raw type to an instantiation yields an "unchecked conversion" warning. 

Example (of assignment compatibility): 

ArrayList         rawList    = new ArrayList(); 
ArrayList<String> stringList = new ArrayList<String>();
rawList    = stringList;
stringList = rawList;      // unchecked warning
The "unchecked" warning indicates that the compiler does not know whether the raw type ArrayList really contains strings.  A raw type ArrayList can in principle contain any type of object and is similar to a ArrayList<Object> .
LINK TO THIS GenericTypes.FAQ201
REFERENCES Why are raw types permitted?
Can I use a raw type like any other type?
How does the raw type relate to instantiations of the corresponding generic type?

Why are raw types permitted?

To facilitate interfacing with non-generic (legacy) code.
Raw types are permitted in the language predominantly to facilitate interfacing with non-generic (legacy) code. 

If, for instance, you have a non-generic legacy method that takes a List as an argument, you can pass a parameterized type such as List<String> to that method.  Conversely, if you have a method that returns a List , you can assign the result to a reference variable of type List<String> , provided you know for some reason that the returned list really is a list of strings. 

Example (of interfacing with legacy code using raw types): 

class SomeLegacyClass {
  public void setNames(List c) { ... }
  public List getNames() { ... }
}

final class Test {
  public static void main(String[] args) {
    SomeLegacyClass obj = new SomeLegacyClass();
    List<String> names = new LinkedList<String>();
    ...  fill list ...

    obj.setNames(names);

    names = obj.getNames();    // unchecked warning
  }
}

A List<String> is passed to the setNames method that asks for an argument of the raw type List .  The  conversion from a List<String> to a  List is safe because a method that can handle a heterogeneous list of objects can certainly cope with a list of strings. 

The getNames method returns a raw type List , which we assign to a variable of type List<String> .  The compiler has not enough information to ensure that the list returned really is a list of strings.  Despite of that, the compiler permits the conversion from the raw type List to the more specific type List<String> , in order to allow this kind of mixing of non-generic and generic Java code. Since the conversion from List to List<String> is not type-safe, the assignment is flagged as an "unchecked assignment". 

The use of raw types in code written after the introduction of genericity into the Java programming language is discouraged. According to the Java Language Specification, it is possible that future versions of the Java programming language will disallow the use of raw types.

LINK TO THIS GenericTypes.FAQ202
REFERENCES What are raw types?
Can I use a raw type like any other type?
How does the raw type relate to instantiations of the corresponding generic type?

Can I use a raw type like any other type?

Yes, but certain uses will result in "unchecked" warnings.
Raw types can be used like regular types without any restrictions, except that certain uses will result in "unchecked" warnings. 

Example (of a parameterized type): 

interface Copyable<T> {
  T copy();
}
final class Wrapped <Elem extends Copyable<Elem>> {
  private Elem theObject; 

  public Wrapped( Elem arg) { theObject = arg.copy(); }

  public void setObject( Elem arg) { theObject = arg.copy(); }

  public Elem getObject() { return theObject.copy(); }

  public boolean equals(Object other) {
    if (other == null) return false;
    if (! (other instanceof Wrapped))  return false;
    return (this.theObject.equals(((Wrapped)other).theObject));
  }
}

Methods or constructors of a raw type have the signature that they would have after type erasure.  A method or constructor call to a raw type generates an unchecked warning if the erasure changes the argument types. 

Example (same as above - after type erasure): 

interface Copyable {
  Object copy();
}
final class Wrapped {
  private Copyable theObject; 

  public Wrapped( Copyable arg) { theObject = arg.copy(); }

  public void setObject( Copyable arg) { theObject = arg.copy(); }

  public Copyable getObject() { return theObject.copy(); }

  public boolean equals(Object other) {
    if (other == null) return false;
    if (! (other instanceof Wrapped))  return false;
    return (this.theObject.equals(((Wrapped)other).theObject));
  }
}

Invocation of a method or constructor, whose argument type changed in the course of type erasure is unsafe and is flagged as an "unchecked" operation.  For instance, the method setObject has the signature void setObject(Copyable) after type erasure and its invocation results in an "unchecked" warning.  The invocation is unsafe because the compiler cannot ensure that the argument passed to the method is compatible to the "erased" type that the type parameter Elem stands for. 

Example (using the raw type): 

class MyString implements Copyable<MyString> {
  private StringBuilder buffer;
  public MyString(String s) { buffer = new StringBuilder(s); }
  public MyString copy() { return new MyString(buffer.toString()); }
  ...
}
class Test {
  private static void test( Wrapped wrapper) {
    wrapper. setObject (new MyString("Deutsche Bank"));  // unchecked warning
    Object s = wrapper. getObject ();
  }
  public static void main(String[] args) {
    Wrapped<MyString> wrapper = new Wrapped<MyString>(new MyString("Citibank"));
    test(wrapper);
  }
}
If the method's argument type is not changed by type erasure, then the method call is safe.  For instance, the method getObject has the signature Copyable getObject(void) after type erasure and its invocation is safe and warning-free. 

Fields of a raw type have the type that they would have after type erasure.   A field assignment to a raw type generates an unchecked warning if erasure changes the field type.  In our example, the field theObject of the raw type Wrapped is changed by type erasure and is of type Copyable after type erasure. 

If the theObject field  were public and we could assign to it, the assignment would be unsafe because the compiler cannot ensure that the value being assigned really is of type Elem .  Yet the assignment is permitted and flagged as an "unchecked" assignment. Reading the field  is safe and does not result in a warning. 

LINK TO THIS GenericTypes.FAQ203
REFERENCES What is type erasure?
How does the raw type relate to instantiations of the corresponding generic type?
Can I use a type parameter as part of its own bounds?

 

Wildcard Instantiations

What is a wildcard parameterized type?

An instantiation of a generic type where the type argument is a wildcard (as opposed to a concrete type).
A wildcard parameterized type is an instantiation of a generic type where at least one type argument is a wildcard.  Examples of wildcard parameterized types are Collection<?> , List<? extends Number> , Comparator<? super String> and Pair<String,?> . A wildcard parameterized type denotes a family of types comprising concrete instantiations of a generic type.  The kind of the wildcard being used determines which concrete parameterized types belong to the family.  For instance, the wildcard parameterized type Collection<?> denotes the family of all instantiations of the Collection interface regardless of the type argument.  The wildcard parameterized type List<? extends Number> denotes the family of all list types where the element type is a subtype of  Number .  The wildcard parameterized type Comparator<? super String> is the family of all instantiations of the Comparator interface for type argument types that are supertypes of String

A wildcard parameterized type is not a concrete type that could appear in a new expression.  A wildcard parameterized type is similar to an interface type in the sense that reference variables of a wildcard parameterized type can be declared, but no objects of the wildcard parameterized type can be created.  The reference variables of a wildcard parameterized type can refer to an object that is of a type that belongs to the family of types that the wildcard parameterized type denotes. 

Examples: 

Collection<?> coll = new ArrayList<String>();
List<? extends Number> list = new ArrayList<Long>();
Comparator<? super String> cmp = new RuleBasedCollator("< a< b< c< d");
Pair<String,?> pair = new Pair<String,String>();
Counter Example:
List<? extends Number> list = new ArrayList<String>();  // error
Type String is not a subtype of Number and consequently ArrayList<String> does not belong to the family of types denoted by List<? extends Number> . For this reason the compiler issues an error message.
LINK TO THIS GenericTypes.FAQ301
REFERENCES What is a wildcard?
Can I use a wildcard parameterized type like any other type?

What is the unbounded wildcard parameterized type?

An instantiation of a generic type where all type arguments are the unbounded wildcard " ? ".
Examples of unbounded wildcard parameterized types are Pair<?,?> and Map<?,?>

The unbounded wildcard parameterized type is assignment compatible with all instantiations of the correspinding generic type.  Assignment of another instantiation to the unbounded wildcard instantiation is permitted without warnings; assignment of the unbounded wildcard instantiation to another instantiation is illegal. 

Example (of assignment compatibility): 

ArrayList <?>       anyList    = new ArrayList<Long>(); 
ArrayList<String> stringList = new ArrayList<String>();
anyList    = stringList;
stringList = anyList;      // error
The unbounded wildcard parameterized type is kind of the supertype of all other instantiations of the generic type: "subtypes" can be assigned to the "unbounded supertype", not vice versa.
LINK TO THIS GenericTypes.FAQ302
REFERENCES How do unbounded wildcard instantiations of a generic type relate to other instantiations of the same generic type?

What is the difference between the unbounded wildcard parameterized type and the raw type?

The compiler issues error messages for an unbounded wildcard parameterized type while it only reports "unchecked" warnings for a raw type.
In code written after the introduction of genericity into the Java programming language you would usually avoid use of raw types, because it is discouraged and raw types might no longer be supported in future versions of the language (according to the Java Language Specification).  Instead of the raw type you can use the unbounded wildcard parameterized type. 

The raw type and the unbounded wildcard parameterized type have a lot in common.  Both act as kind of a supertype of all instantiations of the corresponding generic type.  Both are so-called reifiable types. Reifiable types can be used in instanceof expressions and as the component type of arrays, where non-reifiable types (such as concrete and bounded wildcard parameterized type) are not permitted. 

In other words, the raw type and the unbounded wildcard parameterized type are semantically equivalent.  The only difference is that the compiler applies stricter rules to the unbounded wildcard parameterized type than to the corresponding raw type. Certain operations performed on the raw type yield "unchecked" warnings.  The same operations, when performed on the corresponding  unbounded wildcard parameterized type, are rejected as errors. 

LINK TO THIS GenericTypes.FAQ303
REFERENCES What is the raw type?
What is the unbounded wildcard parameterized type?
What is a reifiable type?
How do parameterized types fit into the Java type system?
How does the raw type relate to instantiations of the corresponding generic type?
How do instantiations of a generic type relate to  instantiations of other generic types?
How do unbounded wildcard instantiations of a generic type relate to other instantiations of the same generic type?
How do wildcard instantiations with an upper bound relate to other instantiations of the same generic type?
How do wildcard instantiations with a lower bound relate to other instantiations of the same generic type?

Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type?

It depends on the kind of wildcard.
Using an object through a reference variable of a wildcard parameterized type is restricted. Consider the following class: 

Example (of a generic class): 

class Box<T> {
  private T t;
  public Box(T t) { this.t = t; }
  public void put(T t) { this.t = t;}
  public T take() { return t; }
  public boolean equalTo(Box<T> other) { return this.t.equals(other.t); }
  public Box<T> copy() { return new Box<T>(t); }
}
When we use a reference variable of a wildcard instantiation of type Box to access methods and fields of the referenced object the compiler would reject certain invocations. 

Example (of access through a wildcard parameterized type): 

class Test {
  public static void main(String[] args) {
    Box<?> box = new Box<String>("abc");

    box.put("xyz");     // error
    box.put(null);     // ok

    String s = box.take();  // error
    Object o = box.take();  // ok

    boolean equal = box.equalTo(box);  // error
    equal = box.equalTo(new Box<String>("abc")); // error

    Box<?> box1 = box.copy();   // ok
    Box<String> box2 = box.copy();  // error
  }
}

In a wildcard parameterized type such as Box<?> the type of the field and the argument and the return types of the methods would be unknown.  It is like the field t would be of type " ? " and the put method would take an argument of type " ? " and the take method would return a " ? " and so on. 

In this situation the compiler does not let us assign anything to the field or pass anything to the put method. The reason is that the compiler cannot make sure that the object that we are trying to pass as an argument to a method is of the expected type, since the expected type is unknown. Similarly, the compiler does not know of which type the field is and cannot check whether we are assigning an object of the correct type, because the correct type is not known. 

In contrast, the take method can be invoked and it returns an object of an unknown type, which we can assign to a reference variable of type Object

Similar effects can be observed for methods such as like equalTo and copy , which  have a parameterized argument or return type and the type parameter T appears as type argument of the parameterized argument or return type. 

Consider a generic class with methods that use the type parameter in the argument or return type of its methods: 

Example (of a generic class): 

class Box <T> {
  private T t;
  public Box(T t) { this.t = t; }
  public Box( Box<? extends T > box) { t = box.t; }
  ...
  public boolean equalTo( Box< T > other) { return this.t.equals(other.t); }
  public Box< T > copy() { return new Box<T>(t); }

  public Pair< T , T > makePair() { return new Pair<T,T>(t,t); }
  public Class<? extends T > getContentType() { ... }
  public int compareTo( Comparable<? super T > other) { return other.compareTo(t); }
}

The type parameter T can appear as the type argument of a parameterized argument or return type, like in method makePair , which returns a Pair<T,T> . But it can also appear as part of the type argument of a parameterized argument or return type, namely as bound of a wildcard, like in method geteContentType , which returns a value of type Class<? extends T> .  Which methods can or must not be invoked through a wildcard instantiation depends not only on the type of the wildcard instantiation (unbounded or bounded with upper or lower bound), but also on the use of the type parameter (as type argument or as wildcard bound). 

The restriction are fairly complex in detail, because they depend on the type of the wildcard (unbounded or bounded with upper or lower bound).  So far we have only seen Box<?> , that is, the unbounded wildcard instantiation.  Which fields and methods are accessible through references of other wildcard instantiations?  In addition, the rules depend on the way in which a method uses the type parameter in the method signatures (as the type of an argument or the return type or as the type argument of a parameterized argument or return type).  A comprehensive discussion can be found in the FAQ entries listed in the reference section below.

LINK TO THIS GenericTypes.FAQ304
REFERENCES Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type?
Which methods that use the type parameter in the argument or return type are accessible in an unbounded wildcard parameterized type?
Which methods that use the type parameter in the argument or return type are accessible in an upper bound wildcard parameterized type?
Which methods that use the type parameter in the argument or return type are accessible in a lower bound wildcard parameterized type?
Which methods that use the type parameter as type argument of a parameterized argument or return type are accessible in a wildcard parameterized type?
Which methods that use the type parameter as upper wildcard bound in a parameterized argument or return type are accessible in a wildcard parameterized type?
Which methods that use the type parameter as lower wildcard bound in a parameterized argument or return type are accessible in a wildcard parameteriezd type?
In a wildcard parameterized type, can I read and write fields whose type is the type parameter?

Can I use a wildcard parameterized type like any other type?
 
No.  A wildcard parameterized type is not a type in the regular sense (different from a non-parameterized class/interface or a raw type).
Wildcard parameterized types can be used for typing (like non-parameterized classes and interfaces): 
  • as argument and return types of methods
  • as type of a field or local reference variable 
  • as component type of an array
  • as type argument of other parameterized types
  • as target type in casts 
Wildcard parameterized type can NOT be used for the following purposes (different from non-parameterized classes and interfaces): 
  • for creation of objects 
  • for creation of arrays (except unbounded wildcard)
  • in exception handling
  • in instanceof expressions (except unbounded wildcard)
  • as supertypes
  • in a class literal
LINK TO THIS GenericTypes.FAQ305
REFERENCES

Can I create an object whose type is a wildcard parameterized type?
 
No, not directly.
Objects of a wildcard parameterized type are not particularly useful, mainly because there is not much you can do with the object.  You can access an object of a wildcard parameterized type only through a reference of that wildcard parameterized type, and such a reference gives only restricted access to the referenced object.  Basically, the wildcard parameterized type is too abstract to be useful.  For this reason, the creation of objects of a wildcard parameterized type is discouraged: it is illegal that a wildcard parameterized type appears in a  new expression.

Example (of illegal creation of objects of a wildcard parameterized type ): 

ArrayList<String> list = new ArrayList<String>();
... populate the list ...

ArrayList<?> coll1 = new ArrayList <?> (); // error
ArrayList<?> coll2 = new ArrayList <?> (10); // error
ArrayList<?> coll3 = new ArrayList <?> (list); // error

The compiler rejects all attempts to create an object of the wildcard type  ArrayList<?> .

In a way, a wildcard parameterized type is like an interface type:  you can declare reference variables of the type, but you cannot create objects of the type.  A reference variable of an interface type or a wildcard parameterized type can refer to an object of a compatible type.  For an interface, the compatible types are the class (or enum) types that implement the interface.  For a wildcard parameterized type, the compatible types are the concrete instantiations of the corresponding generic type that belong to the family of instantiations that the wildcard denotes. 

Example (comparing interface and wildcard parameterized type ): 

Cloneable clon1 = new Date();
Cloneable clon2 = new Cloneable();     // error

ArrayList<?> coll1 = new ArrayList <String> ();
ArrayList<?> coll2 = new ArrayList <?> (); // error

The code snippet above illustrates the similarity between an interface and a wildcard parameterized type, using the interface Cloneable and the wildcard parameterized type ArrayList<?> as examples.  We can declare reference variables of type Cloneable and ArrayList<?> , but we must not create objects of type Cloneable and ArrayList<?> .

Interestingly, the compiler's effort to prevent the creation of objects of a wildcard parameterized type can be circumvented.  It is unlikely that you will ever want to create an object of a wildcard parameterized type, but should you ever need one, there's the workaround (see  TechnicalDetails.FAQ609 ).

LINK TO THIS GenericTypes.FAQ306
REFERENCES What is a wildcard parameterized type?
Which methods and fields are accessible/inaccessible through a reference variable of a wildcard type? Can I use a wildcard instantiation like any other type?
What is type argument inference?
Is it really impossible to create an object whose type is a wildcard parameterized type?

Can I create an array whose component type is a wildcard parameterized type?
 
No, because it is not type-safe.
The rationale is the same as for concrete parameterized types: a wildcard parameterized type , unless it is an unbounded wildcard parameterized type , is a non-reifiable type and arrays of non-reifiable types are not type-safe. 

The array store check cannot be performed reliably because a wildcard parameterized type that is not an unbounded wildcard parameterized type has a non-exact runtime type. 

Example (of the consequences): 

Object[] numPairArr = new Pair<? extends Number,? extends Number>[10]; // illegal
numPairArr[0] = new Pair<Long,Long>(0L,0L);     // fine
numPairArr[0] = new Pair<String,String>("",""); // should fail, but would succeed
The array store check would have to check whether the pair added to the array is of type Pair<? extends Number,? extends Number> or of a subtype thereof. Obviously, a Pair<String,String> is not of a matching type and should be rejected with an ArrayStoreException .  But the array store check does not detect any type mismatch, because the JVM can only check the array's runtime component type, which is Pair[] after type erasure, against the element's runtime type, which is Pair after type erasure. 
LINK TO THIS GenericTypes.FAQ307
REFERENCES What does type-safety mean?
Can I create an array whose component type is a concrete parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
What is a reifiable type?

Can I declare a reference variable of an array type whose component type is a bounded wildcard parameterized type?
 
Yes, you can, but you should not, because it is neither helpful nor type-safe.
The rationale is the same as for concrete parameterized types: a wildcard parameterized type , unless it is an unbounded wildcard parameterized type , is a non-reifiable type and arrays of non-reifiable types must not be created.  Hence it does not make sense to have a reference variable of such an array type because it can never refer to array of its type.  All that it can refer to is null , an array whose component type is a non-parameterized subtype of the instantiations that belong to the type family denoted by the wildcard, or an array whose component type is the corresponding raw type. Neither of these cases is overly useful, yet they are permitted. 

Example (of an array reference variable with wildcard parameterized component type): 

Pair<? extends Number,? extends Number>[] arr = null;  // fine
arr = new Pair<? extends Number,? extends Number>[2] // error: generic array creation
The code snippet shows that a reference variable of type Pair<? extends Number,? extends Number>[] can be declared, but the creation of such an array is illegal.  But we can have the reference variable of type Pair<? extends Number,? extends Number>[] refer to an array of a non-parameterized subtype of any of the concrete instantiations that belong to the type family denoted by Pair<? extends Number,? extends Number> . (Remember, wildcard parameterized types cannot be used as supertypes; hence a non-parameterized subtype must be a subtype of a concrete parameterized type .) 

Example (of another array reference variable with parameterized component type): 

class Point extends Pair<Double,Double> { ... }

Pair<? extends Number,? extends Number>[] arr = new Point[2] ;    // fine

Using a reference variable of type Pair<? extends Number,? extends Number>[] offers no advantage over using a variable of the actual type Point[] .  Quite the converse; it is an invitation for making mistakes. 

Example (of an array reference variable refering to array of subtypes; not recommended): 

Pair<? extends Number,? extends Number>[] arr = new Point[2];
arr[0] = new Point(-1.0,1.0);  // fine
arr[1] = new Pair<Number,Number>(-1.0,1.0); // fine (causes ArrayStoreException)
arr[2] = new Pair<Integer,Integer>(1,2); // fine (causes ArrayStoreException)
The compiler  permits code for insertion of elements of type Pair< Number,Number > or Pair<Integer,Integer> into the array through the reference variable of type Pair<? extends Number,? extends Number>[] . Yet, at runtime, this insertion will always fail with an ArrayStoreException because we are trying to insert a Pair into a Point[] .   The debatable insertions would be flagged as errors and thereby prevented if we used the actual type of the array, namely Point[] instead of Pair<?extends Number,? extends Number>[]

In essence, you should better refrain from using array reference variable whose component type is a wildcard parameterized type.  Note, that the same holds for array reference variable whose component type is a concrete parameterized type. Only an array reference variable whose component type is an unbounded wildcard parameterized type make sense. This is because an unbounded wildcard parameterized type is a reifiable type and arrays with a reifiable component type can be created;  the array reference variable can refer to an array of its type and the deficiencies discussed above simply do not exist for unbounded wildcard arrays. 
 

LINK TO THIS GenericTypes.FAQ307A
REFERENCES What does type-safety mean?
Can I create an array whose component type is a wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is a concrete parameterized type?
Can I create an array whose component type is a concrete parameterized type?
Can I declare a reference variable of an array type whose component type is an unbounded wildcard parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
What is a reifiable type?

Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
 
Because it is type-safe.
The rationale is related to the rule for other instantiations of a generic type: an unbounded wildcard parameterized type is a reifiable type and arrays of reifiable types are type-safe, in contrast to arrays of non-reifiable types, which are not safe and therefore illegal. The problem with the unreliable array store check (the reason for banning arrays with a non-reifiable component type) does not occur if the component type is reifiable. 

Example (of array of unbounded wildcard parameterized type ): 

Object[] pairArr = new Pair<?,?>[10] ;        // fine
pairArr[0] = new Pair <Long,Long>(0L,0L);     // fine
pairArr[0] = new Pair <String,String>("",""); // fine 
pairArr[0] = new ArrayList <String>();        // fails with ArrayStoreException
The array store check must check whether the element  added to the array is of type Pair<?,?> or of a subtype thereof.  In the example the two pairs, although of different type, are perfectly acceptable array elements. And indeed, the array store check, based on the non-exact runtime type Pair , accepts the two pairs and correctly sorts out the "alien" ArrayList object as illegal by raising an ArrayStoreException . The behavior is exactly the same as for an array of the raw type, which is not at all surprising because the raw type is a reifiable type as well.
LINK TO THIS GenericTypes.FAQ308
REFERENCES What is a reifiable type?
What does type-safety mean?
What is the raw type?
Can I create an array whose component type is a concrete parameterized type?
Can I create an array whose component type is a wildcard parameterized type?

Can I declare a reference variable of an array type whose component type is an unbounded wildcard parameterized type?
 
Yes.
An array reference variable whose component type is an unbounded wildcard parameterized type (such as Pair<?,?>[] ) is permitted and useful.  This is in contrast to array reference variables with a component type that is a concrete or bounded wildcard parameterized type (such as Pair<Long,Long>[] or Pair<? extends Number,? extends Number>[] ); the array reference variable is permitted, but not overly helpful. 

The difference stems from the fact that an unbounded wildcard parameterized type is a reifiable type and arrays with a reifiable component type can be created.  Concrete and bounded wildcard parameterized types are non -reifiable types and arrays with a non-reifiable component type can not be created.  As a result, an array variable with a reifiable component type can refer to array of its type, but this is not possible for the non-reifiable component types. 

Example (of array reference variables with parameterized component types): 

Pair<?,?>[] arr 
  = new Pair<?,?>[2] ;           // fine

Pair<? extends Number,? extends Number>[] arr 
  = new Pair<? extends Number,? extends Number>[2] // error: generic array creation

Pair<Double,Double>[] arr 
  = new Pair<Double,Double>[2] ;    // error: generic array creation

The examples above demonstrate that unbounded wildcard parameterized types are permitted as component type of an array, while other instantiations are not permitted.  In the case of a non-reifiable component type the array reference variable can be declared, but it cannot refer to an array of its type.  At most it can refer to an array of a non-parameterized subtype (or an array of the corresponding raw type), which opens opportunities for mistakes, but does not offer any advantage.
LINK TO THIS GenericTypes.FAQ308A
REFERENCES What is a reifiable type?
Can I create an array whose component type is a wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is a concrete parameterized type?
Can I create an array whose component type is a concrete parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is a bounded wildcard parameterized type?

Can I derive from a wildcard parameterized type?
 
No, a  wildcard parameterized type is not a supertype.
Let us scrutinize an example and see why a wildcard parameterized type cannot be a supertype. Consider the generic interface Comparable

Example (of a generic interface): 

interface Comparable<T> {
  int compareTo(T arg);
}
If it were allowed to subtype from a wildcard instantiation of Comparable , neither we nor the compiler would know what the signature of the compareTo method would be. 

Example (of illegal use of a wildcard parameterized type as a supertype): 

class MyClass implements Comparable <?> { // error
  public int compareTo( ??? arg) { ... }
}
The signatures of methods of a wildcard parameterized type are undefined. We do not know what type of argument the compareTo method is supposed to accept. We can only subtype from concrete instantiations of the Comparable interface, so that the signature of the compareTo method is well-defined. 

Example (of legal use of a concrete parameterized type as a supertype): 

class MyClass implements Comparable <MyClass> {  // fine
  public int compareTo( MyClass arg) { ... }
}
Note that the raw type is, of course, acceptable as a supertype, different from the wildcard parameterized types including the unbounded wildcard parameterized type

Example (of legal use of a raw type as a supertype): 

class MyClass implements Comparable {          // fine
  public int compareTo( Object arg) { ... }
}
LINK TO THIS GenericTypes.FAQ309
REFERENCES What is the raw type?
What is a wildcard parameterized type?
What is the unbounded wildcard parameterized type?
What is the difference between the unbounded wildcard parameterized type and the raw type?

Why is there no class literal for wildcard parameterized types?
 
Because a wildcard parameterized type has no exact runtime type representation.
The rationale is the same as for concrete parameterized types. 

Wildcard parameterized types lose their type arguments when they are translated to byte code in a process called type erasure . As a side effect of type erasure, all  instantiations of a generic type share the same runtime representation, namely that of the corresponding raw type .  In other words, parameterized types do not have type representation of their own. Consequently, there is no point to forming class literals such as List<?>.class , List<? extends Number>.class and List<Long>.class , since no such Class objects exist.  Only the raw type List has a Class object that represents its runtime type. It is referred to as List.class .

LINK TO THIS GenericTypes.FAQ310
REFERENCES What is type erasure?
What is the raw type?
Why is there no class literal for concrete parameterized types?



CONTENT PREVIOUS NEXT INDEX
  © Copyright 1995-2022 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html  last update: 25 Oct 2018