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 - Type Arguments

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 - Type Arguments

Type Arguments

© Copyright 2004-2022 by Angelika Langer.  All Rights Reserved.
Fundamentals Wildcards Wildcard Bounds

Type Arguments


 

Fundamentals

What is a type argument?

A reference type that is used for the instantiation of a generic type or for the instantiation of a generic method, or a wildcard that is used for the instantiation of a generic type .  An actual type argument replaces the formal type parameter used in the declaration of the generic type or method.
Generic types and methods have formal type parameters, which are replaced by actual type arguments when the parameterized type or method is instantiated. 

Example (of a generic type): 

class Box <T> {
  private T theObject;
  public Box( T arg) { theObject = arg; }
  ...
}
class Test {
  public static void main(String[] args) {
    Box <String> box = new Box <String> ("Jack");
  }
}
In the example we see a generic class Box with one formal type parameter T. This formal type parameter is replaced by actual type argument String , when the Box type is used in the test program. 

There are few of rules for type arguments: 

  • The actual type arguments of a generic type are 
    • reference types, 
    • wildcards, or 
    • parameterized types (i.e. instantiations of other generic types). 
  • Generic methods cannot be instantiated using wildcards as actual type arguments. 
  • Type parameters are permitted as actual type arguments.
  • Primitive types are not permitted as type arguments.
  • Type arguments must be within bounds. 
LINK TO THIS TypeArguments.FAQ001
REFERENCES What is a wildcard?
What is a type parameter?
Which types are permitted as type arguments?
Are primitive types permitted as type arguments?
Are wildcards permitted as type arguments?
Are type parameters permitted as type arguments?
Do type parameter bounds restrict the set of types that can be used as type arguments?

Which types are permitted as type arguments?

All references types including parameterized types, but no primitive types.
All reference types can be used a type arguments of a parameterized type or method.  This includes classes, interfaces, enum types, nested and inner types, and array types.  Only primitive types cannot be used as type argument. 

Example (of types as type arguments of a parameterized type): 

List< int >                                 l0;          // error
List< String >                              l1;
List< Runnable >                            l2;
List< TimeUnit >                            l3;
List< Comparable >                          l4;
List< Thread.State >                        l5;
List< int[] >                               l6;
List< Object[] >                            l7;
List< Callable<String> >                    l8;
List< Comparable<? super Long> >            l9;
List< Class<? extends Number> >             l10;
List< Map.Entry<?,?> >                      l11;
The code sample shows that a primitive type such as int is not permitted as type argument. 

Class types, such as String , and interface types, such as Runnable , are permitted as type arguments.  Enum types, such as TimeUnit (see java.util.concurrent.TimeUnit ), are also permitted as type arguments. 

Raw types are permitted as type arguments; Comparable is an example. 

Thread.State is an example of a nested type;  Thread.State is an enum type nested into the Thread class.  Non-static inner types are also permitted.

An array type, such as int[] and Object[] , is permitted as type arguments of a parameterized type or method. 

Parameterized types are permitted as type arguments, including concrete parameterized types such as Callable<String> ,  bounded wildcard parameterized types such as Comparable<? super Long> and Class<? extends Number> , and unbounded wildcard parameterized types such as Map.Entry<?,?>
 

The same types are permitted as explicit type arguments of a generic method. 

Example (of types as type arguments of a generic method): 

List<?> list;
list = Collections.< int >emptyList();              // error
list = Collections.< String >emptyList();
list = Collections.< Runnable >emptyList();
list = Collections.< TimeUnit >emptyList();
list = Collections.< Comparable >emptyList();
list = Collections.< Thread.State >emptyList();
list = Collections.< int[] >emptyList();
list = Collections.< Object[] >emptyList();
list = Collections.< Callable<String> >emptyList();
list = Collections.< Comparable<? super Long> >emptyList();
list = Collections.< Class<? extends Number> >emptyList();
list = Collections.< Map.Entry<?,?> >emptyList();
The code sample shows that primitive types such as int are not permitted as type argument of a generic method either. 
LINK TO THIS TypeArguments.FAQ002
REFERENCES What is a type argument?

Are primitive types permitted as type arguments?


No. Only reference types can be used as type arguments.
A parameterized type such as List<int> or Set<short> is illegal.  Only reference types can be used for instantiation of generic types and methods. Instead of List<int> we must declare a List<Integer >, using the corresponding wrapper type as the type argument. 

The lack of primitive type instantiations is not a major restriction in practice (except for performance reasons), because autoboxing and auto-unboxing hides most of the nuisance of wrapping and unwrapping primitive values into their corresponding wrapper types. 

Example (of autoboxing): 

int[] array = {1,2,3,4,5,6,7,8,9,10};
List<Integer> list = new LinkedList<Integer>();
for (int i : array) 
  list.add(i);        // autoboxing
for (int i=0;i<list.size();i++)
  array[i] = list.get(i);      // auto-unboxing
Here we insert primitive type int values to the list of Integer s, relying on autoboxing, which is the automatic conversion from the primitve type to the corresponding wrapper type. Similarly, we extract primitive type int values from the list,  relying on auto-unboxing, which is the automatic conversion from the wrapper type to the corresponding primitive type. 
 

Note, that the lack of primitive type instantiations incurs a performance penalty.  Autoboxing and -unboxing make the use of wrapper type instantiations of generic types very convenient and concise in the source code.  But the concise notation hides the fact that behind the curtain the virtual machine creates and uses lots of wrapper objects, each of which must be allocated and later garbage collected. The higher performance of direct use of primitive type values cannot be achieved with generic types.  Only a regular (i.e., non-generic) type can provide the optimal performance of using primitive type values. 

Example: 

class Box <T> {
  private T theObject;
  public Box( T arg) { theObject = arg; }
  public T get() { return theObject; }
  ...
}
class BoxOfLong {
  private long theObject;
  public BoxOfLong( long arg) { theObject = arg; }
  public long get() { return theObject; }
  ...
}
class Test {
  public static void main(String[] args) {
    long result;

    Box <Long> box = new Box <Long> (0L);  // autoboxing
    result = box.get();          // auto-unboxing

    Box <long> box = new Box <long> (0L);  // error
    result = box.get();

    BoxOfLong box = new BoxOfLong(0L); 
    result = box.get();
  }
}

The example illustrates that the instantiation of the Box type for type Long leads to the inevitable overhead of boxing and unboxing.  The instantiation on the primitive type long does not help, because it is illegal.  Only a dedicated non-generic BoxOfLong type eliminates the overhead by using the primitive type long .
LINK TO THIS TypeArguments.FAQ003
REFERENCES What is a type argument?
Which types are permitted as type arguments?

Are wildcards permitted as type arguments?

For instantiation of a generic type, yes. For instantiation of a generic method, no.
A wildcard is a syntactic construct that denotes a family of types. 

All wildcards can be used as type arguments of a parameterized type.  This includes the unbounded wildcard as well as wildcards with an upper or lower bound. 

Examples: 

List< ? >                 l0; 
List< ? extends Number >  l1;
List< ? super Long >      l2;
Wildcards can not be used as type arguments of a generic method. 

Examples: 

list = Collections.< ? >emptyList(); //error
list = Collections.< ? extends Number >emptyList(); //error
list = Collections.< ? super Long >emptyList(); //error
LINK TO THIS TypeArguments.FAQ004
REFERENCES What is a wildcard?
What is an unbounded wildcard?
What is a bounded wildcard?

Are type parameters permitted as type arguments?

Yes.
Type parameters of a generic type or method can be used as arguments of parameterized types or methods. 

Example (of instantiations of a generic type using a type parameter as type argument): 

class someClass <T> {
  public List<T> someMethod() {
     List< T > list = Collections.< T >emptyList();
     ...
     return list;
  }
  public static <S> void anotherMethod(S arg) {
     List< S > list = Collections.< S >emptyList();
     ...
  }
}
The example above demonstrates how the type parameter T of the enclosing generic class and the type parameter S of a generic method can be used as type arguments to both a parameterized type, namely List , and a generic method, namely emptyList .
LINK TO THIS TypeArguments.FAQ005
REFERENCES What is a type argument?
What is a type parameter?
What is a parameterized (or generic) method?
What is a parameterized (or generic) type?

Do type parameter bounds restrict the set of types that can be used as type arguments?

Yes, type arguments must be within bounds. 
When a formal type parameter is declared with one or several bounds, then the actual type argument must be a subtype of all of the bounds specified for the respective formal type parameter. 

Examples: 

class Wrapper<T extends Comparable <T> > implements Comparable <Wrapper<T>> {
  private final T theObject;
  public Wrapper(T t) { theObject = t; }
  public T getWrapper() { return theObject; }
  public int compareTo(Wrapper <T> other) { return theObject.compareTo(other.theObject); }
}


Wrapper <String>            wrapper1 = new Wrapper <String> ("Oystein");
Wrapper <? extends Number> wrapper2 = new Wrapper <Long> (0L);
Wrapper <?>                 wrapper3 = new Wrapper <Date> (new Date());
Wrapper <Number>            wrapper4 = new Wrapper <Number> (new Long(0L));  // error
Wrapper <int>               wrapper5 = new Wrapper <int> (5);  // error
Comparable<T> uses a type parameter as its type argument. 
Comparable<Wrapper<T>> uses an instantiation of a parameterized type as type argument. 
Wrapper<String> and Wrapper<Long> have concrete reference types as type arguments. 
Wrapper<? extends Number> and Wrapper<?> use wildcards as type arguments. 
Wrapper<Number> is illegal because Number is not a subtype of Comparable<Number> and is not within bounds. 
Wrapper<int> is illegal because primitive types are not allowed as type arguments. 
LINK TO THIS TypeArguments.FAQ006
REFERENCES What is a type parameter?
What is a bounded type parameter?

Do I have to specify a type argument when I want to use a generic type?

No; you can use the so-called raw type, which is the generic type without type arguments.
A generic type without any type arguments is called a raw type . Examples of raw types are List , Set , Comparable , Iterable , etc. 

Raw types are permitted for compatilibity between generic and non-generic (legacy) Java APIs. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly 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 TypeArguments.FAQ007
REFERENCES What is the raw type?
Can I use a raw type like any other type?
How does the raw type relate to instantiations of the corresponding generic type?
Where can I find a specification of the Java generics language features?

Do I have to specify a type argument when I want to invoke a generic method?
 
No; a generic method can be used without type arguments.
A generic method can be invoked like a regular method, that is, without specification of the type arguments.  In such a case the compiler will automatically infer the type arguments from the static types of the method arguments or the context of the method invocation.  This process is known as type argument inference .
LINK TO THIS TypeArguments.FAQ008
REFERENCES What is type argument inference?
What is explicit type argument specification?

 

Wildcards

What is a wildcard?

A syntactic construct that denotes a family of types.
A wildcard describes a family of types.  There are 3 different flavors of wildcards: 
  • " ? " - the unbounded wildcard. It stands for the family of all types.
  • " ? extends Type " - a wildcard with an upper bound. It stands for the family of all types that are subtypes of Type , type Type being included.
  • " ? super Type " - a wildcard with a lower bound. It stands for the family of all types that are supertypes of Type , type Type being included.
Wildcards are used to declare so-called wildcard parameterized types, where a wildcard is used as an argument for instantiation of generic types. Wildcards are useful in situations where no or only partial knowledge about the type argument of a parameterized type is required.
LINK TO THIS TypeArguments.FAQ101
REFERENCES What is a wildcard parameterized type?
If a wildcard appears repeatedly in a type argument section, does it stand for the same type?
What is a wildcard bound?
What is an unbounded wildcard?
What is a bounded wildcard?
Which super-subset relationships exist among wildcards?

What is an unbounded wildcard?

A wildcard without a bound.
The unbounded wildcard looks like " ? " and stands for the family of all types. 

The unbounded wildcard is used as argument for instantiations of generic types.  The unbounded wildcard is useful in situations where no knowledge about the type argument of a parameterized type is needed. 

Example: 

void printCollection( Collection<?> c){   // an unbounded wildcard parameterized type
  for (Object o : c){
    System.out.println(o);
  }
}
The printCollection method does not require any particular properties of the elements contained in the collection that it prints. For this reason it declares its argument using an unbounded wildcard parameterized type, saying that any type of collection regardless of the element type is welcome.
LINK TO THIS TypeArguments.FAQ102
REFERENCES What is a wildcard?
What is a wildcard parameterized type?
What is an unbounded wildcard parameterized type?
How do unbounded wildcard instantiations of a parameterized type relate to other instantiations of the same generic type?
Which super-subset relationships exist among wildcards?

What is a bounded wildcard?

A wildcard with either an upper or a lower bound.
A wildcard with an upper bound looks like " ? extends Type " and stands for the family of all types that are subtypes of Type , type Type being included.  Type is called the upper bound

A wildcard with a lower bound looks like " ? super Type " and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound

Bounded wildcards are used as arguments for instantiation of generic types.  Bounded wildcards are useful in situations where only partial knowledge about the type argument of a parameterized type is needed, but where unbounded wildcards carry too little type information. 

Example: 

public class Collections {
  public static <T> void copy 
  ( List<? super T> dest, List<? extends T> src) {  // bounded wildcard parameterized types
      for (int i=0; i<src.size(); i++)
        dest.set(i,src.get(i));
  }
}
The copy method copies elements from a source list into a destination list.  The destination list must be capable of holding the elements from the source list.  We express this by means of bounded wildcards: the output list is required to have an element type with a lower bound T and the input list must have an element type with an upper bound T

Let's study an example to explore the typical use of bounded wildcards and to explain why unbounded wildcards do not suffice. It's the example of the copy method mentioned above.  It copies elements from a source list into a destination list.  Let's start with a naive implementation of such a copy method. 

Example (of a restrictive implementation of a copy method): 

public class Collections {
  public static <T> void copy( List<T> dest, List<T> src) {  // uses no wildcards
      for (int i=0; i<src.size(); i++)
        dest.set(i,src.get(i));
  }
}
This implementation of a copy method is more restrictive than it need be, because it requires that both input and output collection must be lists with the exact same type. For instance, the following invocation - although perfectly sensible - would lead to an error message: 

Example (of illegal use of the copy method): 

List<Object> output = new ArrayList< Object >();
List<Long>    input = new ArrayList< Long >();
...
Collections.copy(output,input);  // error: illegal argument types
The invocation of the copy method is rejected because the declaration of the method demands that both lists must be of the same type.  Since the source list is of type List<Long> and the destination list is of type List<Object> the compiler rejects the method call, regardless of the fact that a list of Object references can hold Long s.  If both list were of type List<Object> or both were of type List<Long> the method call were accepted. 

We could try to relax the method's requirements to the argument types and declare wildcard parameterized types as the method parameter types.  Declaring wildcard parameterized types as method parameter types has the advantage of allowing a broader set of argument types.  Unbounded wildcards allow the broadest conceivable argument set, because the unbounded wildcard ? stands for any type without any restrictions.  Let's try using an unbounded wildcard parameterized type.  The method would then look as follows: 

Example (of a relaxed copy method; does not compile): 

public class Collections {
  public static void copy( List<?> dest, List<?> src) {  // uses unbounded wildcards
      for (int i=0; i<src.size(); i++)
        dest.set(i,src.get(i)); // error: illegal argument types
  }
}
It turns out that this relaxed method signature does not compile.  The problem is that the get() method of a List<?> returns a reference pointing to an object of unknown type.  References pointing to objects of unknown type are usually expressed as a reference of type Object .  Hence List<?>.get() returns an Object

On the other hand, the set() method of a List<?> requires something unknown, and "unknown" does not mean that the required argument is of type Object .  Requiring an argument of type Object would mean accepting everything that is derived of Object .  That's not what the set() method of a List<?> is asking for. Instead, "unknown" in this context means that the argument must be of a type that matches the type that the wildcard ? stands for.  That's a much stronger requirement than just asking for an Object

For this reason the compiler issues an error message:  get() returns an Object and set() asks for a more specific, yet unknown type. In other words, the method signature is too relaxed.  Basically,  a signature such as void copy( List<?> dest, List<?> src) is saying that the method takes one type of list as a source and copies the content into another - totally unrelated - type of destination list.  Conceptually it would allow things like copying a list of apples into a list of oranges.  That's clearly not what we want. 

What we really want is a signature that allows copying elements from a source list into a destination list with a specific property, namely that it is capable of holding the source list's elements. Unbounded wildcards are too relaxed for this purpose, as we've seen above, but bounded wildcards are suitable in this situation.  A bounded wildcard carries more information than an unbounded wildcard. 

In our example of a copy method we can achieve our goal of allowing all sensible method invocations by means of bounded wildcards, as in the following implementation of the copy method: 

Example (of an implementation of the copy method that uses bounded wildcards): 

public class Collections {
  public static <T> void copy 
  ( List<? super T> dest, List<? extends T> src) {  // uses bounded wildcards
      for (int i=0; i<src.size(); i++)
        dest.set(i,src.get(i));
  }
}
In this implementation we require that a type T exists that is subtype of the output list's element type and supertype of the input list's element type.  We express this by means of wildcards: the output list is required to have an element type with a lower bound T and the input list must have an element type with an upper bound T

Example (of using the copy method with wildcards): 

List<Object> output = new ArrayList< Object >();
List<Long>    input = new ArrayList< Long >();
...
Collections.copy(output,input);  // fine; T:= Number & Serializabe & Comparable<Number>

List<String> output = new ArrayList< String >();
List<Long>    input = new ArrayList< Long >();
...
Collections.copy(output,input);  // error
 

In the first method call T would have to be a supertype of Long and a subtype of Object , and luckily there is a number of types that fall into this category, namely  Number , Serializable and Comparable<Number> .  Hence the compiler can use any of the 3 types as type argument and the method invocation is permitted. 

The second nonsensical method call is rejected by the compiler, because the compiler realizes that there is no type that is subtype of String and supertype of Long

Conclusion
Bounded wildcards carry more information than unbounded wildcards.  While an unbounded wildcard stands for a representative from the family of all types, a bounded wildcards stands for a represenstative of a family of either super- or subtypes of a type.  Hence a bounded wildcard carries more type information than an unbounded wildcard.  The supertype of such a family is called the upper bound, the subtype of such a family is called the lower bound.

LINK TO THIS TypeArguments.FAQ103
REFERENCES What is a wildcard?
What is a wildcard instantiation?
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 super-subset relationships exist among wildcards?
What is a wildcard bound?
Which types are permitted as wildcard bounds?
What is the difference between a wildcard bound and a type parameter bound?
What is the difference between a Collection<?> and a Collection<Object>?

What do multi-level (i.e., nested) wildcards mean?

It depends. 
A multi-level wildcard is a wildcard that appears as the type argument of a type argument. The instantiations Collection<Pair<String,?>> and Collection<? extends Pair<String,?>> are examples of multi-level wildcards. Multi-level wildcard parameterized types are inherently difficult to interpret, because the wildcard can appear on different levels.  For illustration, let us discuss the difference between a Collection<Pair<String,?>> and a Collection<? extends Pair<String,?>> .  For sake of simplicity, let us assume Pair is a final class. 

The type Collection<Pair<String,?>> is a concrete instantiation of the generic Collection interface.  It is a heterogenous collection of pairs of different types.  It can contain elements of type Pair<String,Long> , Pair<String,Date> , Pair<String,Object> , Pair<String,String> , and so on and so forth. In other words, Collection<Pair<String,?>> contains a mix of pairs of different types of the form Pair<String,?>

The type  Collection<? extends Pair<String,?>> is a wildcard parameterized type; it does NOT stand for a concrete parameterized type.  It stands for a representative from the family of collections that are instantiations of the Collection interface, where the type argument is of the form Pair<String,?> .  Compatible instantiations are Collection<Pair<String,Long>> , Collection<Pair<String,String>> , Collection<Pair<String,Object>> , or Collection<Pair<String,?>> . In other words, we do not know which instantiation of Collection it stands for. 

As a rule of thumb, you have to read multi-level wildcards top-down. 

If the top-level type argument is a concrete type then the instantiation is a concrete type, probably a mixed bag of something, if the wildcard appears further down on a lower level.  In this sense, a Collection<Pair<String,?>> is a collection of pairs of a certain form, that has lots of concrete subtypes. It's similar to a Collection<Object> , which is a collection of a concrete type that has lots of subtypes and is a mixed bag of something that is a subtype of Object

If the top-level type argument is a wildcard, then the type is not concrete.  It is a placeholder for a representative from a family of types. In this sense, a Collection<? extends Pair<String,?>> is a placeholder for a collection instantiated for a particular unknown pair type of a certain form. It's similar to a Collection<?> , which is a placeholder for a specific instantiation of the Collection interface, but it is not a concrete type. 


Here is an example that illustrates the difference between Collection<Pair<String,?>> and Collection<? extends Pair<String,?>>

Example: 

Collection< Pair<String,Long> >        c1 = new ArrayList<Pair<String,Long>>();

Collection< Pair<String,Long> >        c2 = c1;  // fine
Collection< Pair<String,?> >           c3 = c1;  // error
Collection< ? extends Pair<String,?> > c4 = c1; // fine 

Of course, we can assign a Collection<Pair<String,Long>> to a Collection<Pair<String,Long>> .  There is nothing surprising here. 

But we can not assign a Collection<Pair<String,Long>> to a Collection<Pair<String,?>> .  The parameterized type Collection<Pair<String,Long>> is a homogenous collection of  pairs of a String and a Long ;  the parameterized type Collection<Pair<String,?>> is a heterogenous collection of pairs of a String and something of unknown type.  The heterogenous Collection<Pair<String,?>> could for instance contain a Pair<String,Date> and that clearly does not belong into a Collection<Pair<String,Long>> .  For this reason the assignment is not permitted. 

But then, we can assign a Collection<Pair<String,Long>> to a Collection<? extends Pair<String,?>> , because the type Pair<String,Long> belongs to the family of types denoted by the wildcard ? extends Pair<String,?> .  This is because the type family denoted by the wildcard ? extends Pair<String,?> comprises all subtypes of Pair<String,?> .  Since we assumed that Pair is a final type, this type family includes all instantiations of the generic type Pair where the first type argument is String and second type argument is an arbitrary type or wildcard.  The type family includes members such as Pair<String,Long> , Pair<String,Object> , Pair<String,? extends Number> , and Pair<String,?> itself. 
 
 

If we give up the simplification that Pair is a final class, then we must also consider subtypes of Pair

Collection<Pair<String,?>> is then a heterogenous collection of pairs of different types of the form Pair<String,?> , or subtypes thereof . It can contain elements of type Pair<String,Long> , Pair<String,Date> , but also elements of type SubTypeOfPair<String,Date> , SubTypeOfPair<String,Object> , and so on and so forth. 

Collection<? extends Pair<String,?>> stands for a representative from the family of collections that are instantiations of the Collection interface, where the type argument is of the form Pair<String,?> , or subtypes thereof . Compatible parameterized types are Collection<Pair<String,Long>> , Collection<Pair<String,Object>> , but also Collection<SubTypeOfPair<String,Object>> , or Collection<SubTypeOfPair<String,?>>

Here is an example that illustrates the difference between the concrete parameterized type Collection<Pair<String,?>> and the wildcard parameterized type Collection<? extends Pair<String,?>>

Example: 

Collection< SubTypeOfPair<String,Long> > c1 = new ArrayList<SubTypeOfPair<String,Long>>();

Collection< Pair<String,Long> >          c2 = c1;  // error
Collection< SubTypeOfPair<String,Long> > c3 = c1; // fine
Collection< Pair<String,?> >             c4 = c1;  // error
Collection< ? extends Pair<String,?> >   c5 = c1;  // fine 

In this case, we can not assign a Collection<SubTypeOfPair<String,Long>> to a Collection<Pair<String,Long>> , because these two instantiations of the generic type Collection are unrelated and incompatible types.  The Collection<SubTypeOfPair<String,Long>> contains SubTypeOfPair<String,Long> objects, whereas the Collection<Pair<String,Long>> contains a mix of objects of types that are subtypes of type Pair<String,Long> . This includes, but is not limited to objects of type SubTypeOfPair<String,Long> . For this reason a Collection<SubTypeOfPair<String,Long>> cannot be assigned to a Collection<Pair<String,Long>> .

Also, we can not assign a Collection<SubTypeOfPair<String,Long>> to a Collection<Pair<String,?>> because the parameterized type Collection<SubTypeOfPair<String,Long>> is a homogenous collection of  objects of type SubTypeOfPair<String,Long> , whereas the parameterized type Collection<Pair<String,?>> is a heterogenous collection.  The heterogenous Collection<Pair<String,?>> could for instance contain a Pair<String,Date> and that clearly does not belong in a Collection<SubTypeOfPair<String,Long>>

The assignment of a Collection<SubTypeOfPair<String,Long>> to a Collection<? extends Pair<String,?>> is fine because the type SubTypeOfPair<String,Long> belongs to the family of types denoted by the wildcard ? extends Pair<String,?> .  This is because the type family denoted by the wildcard ? extends Pair<String,?> comprises all subtypes of Pair<String,?> .  Since we no longer assumed that Pair is a final type, this type family includes all instantiations of the generic type Pair and any of its subtypes where the first type argument is String and second type argument is an arbitrary type or wildcard.  The type family includes members such as Pair<String,Long> , Pair<String,Object> , Pair<String,? extends Number> , and Pair<String,?> itself, but also SubTypeOfPair<String,Long> , SubTypeOfPair<String,Object> , SubTypeOfPair<String,? extends Number> , and SubTypeOfPair<String,?> .

LINK TO THIS TypeArguments.FAQ104
REFERENCES What is the difference between a Collection<?> and a Collection<Object>?
Which super-subset relationships exist among wildcards?
What is the difference between a Collection<Pair<String,Object>>, a Collection<Pair<String,?>> and a Collection<? extends Pair<String,?>>?

If a wildcard appears repeatedly in a type argument section, does it stand for the same type?

No, each occurrence can stand for a different type.
If the same wildcard appears repeatedly in a type argument section each occurrence of the wildcard refers to a potentially different type.  It is similar to wildcards in a regular expression: in "s??" the wildcard need not stand for the same character.  "see", but also "sea" or "sew" or "saw" would be matching expressions. Each question mark stands for a potentially different character. The same holds for wildcards in Java generics. 

Example (using the same wildcard repeatedly): 

Pair< ? , ? > couple = new Pair< String , String >("Orpheus","Eurydike");
Pair< ? , ? > xmas   = new Pair< String , Date >("Xmas", new Date(104,11,24));
In the example above, the wildcard " ? " can stand for the same type, such as String , but it need not do so.  Each wildcard can stand for a different type, such as String and Date for instance. 

Conversely, different wildcards need not stand for different types.  If the type families denoted by the two different wildcards overlap, then the two different wildcards can stand for the same concrete type. 

Example (using different wildcards): 

Pair< ? extends Appendable , ? extends CharSequence > textPlusSuffix
  = new Pair< StringBuilder , String >(new StringBuilder("log"), ".txt");

Pair< ? extends Appendable , ? extends CharSequence > textPlusText
  = new Pair< StringBuilder , StringBuilder >(new StringBuilder("log"), new StringBuilder(".txt"));

In the examples above, the different wildcards " ? extends Appendable " and " ? extends CharSequence " can stand for different types, such as StringBuilder and String , but they can equally well stand for the same type, such as StringBulder , provided the bounds permit it. 

Below are a couple of examples where the same wildcard appears repeatedly and where the compiler rightly issues an error message. 

In the first example the wildcard appears twice in an parameterized type, namely in Pair<?,?>

Example #1 (demonstrating the incompatibility of one wildcard to another): 

class Pair<S,T> {
  private S first;
  private T second;
  public Pair(S s,T t) { first = s; second = t; }
  ...
  public static void flip( Pair< ? , ? > pair) { 
    Object tmp = pair.first;
    pair.first = pair.second;  // error: incompatible types
    pair.second = tmp;     // error: incompatible types
  }
}
class Test {
  public static void test() {
     Pair<?,?> xmas = new Pair< String , Date >("Xmas",new Date(104,11,24));
     Pair.flip(xmas); 

     Pair<?,?> name = new Pair< String , String >("Yves","Meyer");
     Pair.flip(name); 
  }
}

The fields of the Pair<?,?> may be of different types. For instance, when the flip method is invoked with an argument of type Pair<String,Date> , then first would be of type String , while second is of type Date ,  and the fields cannot be assigned to each other.  Even if the flip method is invoked with an argument of type Pair<String,String> , i.e. both wildcards stand for the same type, namely String , the compiler does not know this inside the implementation of the flip method.  For this reason the compiler issues an error message in the implementation of the flip method when the two fields of unknown - and potentially different types - are assigned to each other. 

In the second example the wildcard appears in an two instantiations of the same generic type, namely in Collection<?>

Example #2 (demonstrating the incompatibility of one wildcard to another): 

class Utilities {
    public static void add( Collection< ? > list1, Collection< ? > list2) {
       for (Object o : list1)
         list2.add(o); // error: incompatible types
    }
}
class Test {
  public static void test() {
    Collection<?> dates   = new LinkedList< Date >();
    Collection<?> strings = new LinkedList< String >();
    add(dates,strings);
    add(strings,strings);
  }
}
The two collections contain elements of two potentially different unknown types.  The compiler complains when elements from one collection are passed to the other collection, because the types of the elements might be incompatible. 

In the third example the wildcard appears in an two instantiations of two different generic type, namely in Collection<? extends CharSequence> and Class<? extends CharSequence>

Example #3 (demonstrating the incompatibility of one wildcard to another): 

class Utilities {
  public static void method( Collection< ? extends CharSequence > coll, 
                            Class     < ? extends CharSequence > type) {
    ...
    coll.add(type.newInstance()); // error: incompatible types
    ...
  }
}
class Test {
  public static void test() {
    List< StringBuilder > stringList = new LinkedList<StringBuilder>();
    method(stringList, String .class);
  }
}
The newInstance method of class Class<? extends CharSequence> creates an object of an unknown subtype of CharSequence , while the collection Collection<? extends CharSequence> holds elements of a potentially different subtype of CharSequence . The compiler complains when the newly created object is passed to the collection, because the collection might hold objects of an incompatible type.
LINK TO THIS TypeArguments.FAQ105
REFERENCES What is a wildcard instantiation?
How can I make sure that the same wildcard stand for the same type?
What is a wildcard bound?
What is an unbounded wildcard?
What is a bounded wildcard?
Which super-subset relationships exist among wildcards?

 

Wildcard Bounds


 

What is a wildcard bound?

A reference type that is used to further describe the family of types denoted by a wildcard.
A wildcard can be unbounded, in which case it is denoted as " ? ".  The unbounded wildcard stands for the family of all types. 

Alternatively a wildcard can have a bound.  There are two types of bounds: upper and lower bounds.  The syntax for a bounded wildcard is either " ? extends SuperType " (wildcard with upper bound) or " ? super SubType " (wildcard with lower bound).  The terms "upper" and "lower" stem from the way, in which inheritance relationships between types are denoted in modeling languages such as UML for instance. 

The bound shrinks the family of types that the wildcard stands for. For instance, the wildcard " ? extends Number " stands for the family of subtypes of Number ; type Number itself is included in the family.  The wildcard " ? super Long "  stands for the family of supertypes of Long ;  type Long itself is included. 

Note, a wildcard can have only one bound. In can neither have both an upper and a lower bound nor several upper or lower bounds.  Constructs such as " ? super Long extends Number "  or  " ? extends Comparable<String> & Cloneable " are illegal.

LINK TO THIS TypeArguments.FAQ201
REFERENCES What is a wildcard?
Which types are permitted as wildcard bounds?
What is the difference between a wildcard bound and a type parameter bound?

Which types are permitted as wildcard bounds?

All references types including parameterized types, but no primitive types.
All reference types can be used as a wildcard bound.  This includes classes, interfaces, enum types, nested and inner types, and array types.  Only primitive types cannot be used as wildcard bound. 

Example (of wildcard bounds): 

List<? extends int >                                 l0;          // error
List<? extends String >                              l1;
List<? extends Runnable >                            l2;
List<? extends TimeUnit >                            l3;
List<? extends Comparable >                          l4;
List<? extends Thread.State >                        l5;
List<? extends int[] >                               l6;
List<? extends Object[] >                            l7;
List<? extends Callable<String> >                    l8;
List<? extends Comparable<? super Long> >            l9;
List<? extends Class<? extends Number> >             l10;
List<? extends Map.Entry<?,?> >                      l11;
List<? extends Enum<?> >                             l12;
The example only shows the various reference types as upper bound of a wildcard, but these type are permitted as lower bound as well. 

We can see that primitive types such as int are not permitted as wildcard bound. 

Class types, such as String , and interface types, such as Runnable , are permitted as wildcard bound.  Enum types, such as TimeUnit (see java.util.concurrent.TimeUnit ) are also permitted as wildcard bound.  Note, that even types that do not have subtypes, such as final classes and enum types, can be used as upper bound.  The resulting family of types has exactly one member then. For instance, " ? extends String " stands for the type family consisting of the type String alone.  Following the same line of logic, the wildcard " ? super Object " is permitted, too, although class Object does not have a supertype.  The resulting type family consists of type Object alone. 

Raw types are permitted as wildcard bound; Comparable is an example. 

Thread.State is an example of a nested type;  Thread.State is an enum type nested into the Thread class.  Non-static inner types are also permitted. 

An array type, such as int[] and Object[] , is permitted as wildcard bound. Wildcards with an array type as a bound denote the family of all sub- or supertypes of the wildcard type.  For instance, " ? extends Object[] " is the family of all array types whose component type is a reference type.  int[] does not belong to that family, but Integer[] does. Similarly, " ? super Number[] " is the family of all supertypes of the array type, such as Object[] , but also Object , Cloneable and Serializable

Parameterized types are permitted as wildcard bound, including concrete parameterized types such as Callable<String> ,  bounded wildcard parameterized types such as Comparable<? super Long> and Class<? extends Number> , and unbounded wildcard parameterized types such as Map.Entry<?,?> .  Even the primordial supertype of all enum types, namely class Enum , can be used as wildcard bound. 
 

LINK TO THIS TypeArguments.FAQ202
REFERENCES What is a wildcard?
What is a wildcard bound?

What is the difference between a wildcard bound and a type parameter bound?

A wildcard can have only one bound, while a type parameter can have several bounds. 
A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter. 
Wildcard bounds and type parameter bounds are often confused, because they are both called bounds and have in part similar syntax. 

Example (of type parameter bound and wildcard bound): 

class Box< T extends Appendable & Flushable > {

  private T theObject;
  public Box(T arg)                { theObject = arg; } 
  public Box(Box< ? extends T > box) { theObject = box.theObject; }
  ...
}

The code sample above shows a type parameter T with two bounds, namely Appendable and Flushable , and a wildcard with an upper bound T

The type parameter bounds give access to their non-static methods.  For instance, in the example above, the bound Flushable makes is possible that the flush method can be invoked on variables of type T .  In other words, the compiler would accept an expression such as theObject.flush().

The wildcard bound describes the family of types that the wildcard stands for. In the example, the wildcard " ? extends T " denotes the family of all subtypes of T .  It is used in the argument type of a constructor and permits that box objects of a box type from the family Box<? extends T> can be supplied as constructor arguments.  It allows that a Box<Writer> can be constructed from a Box<PrintWriter> , for instance. 

The syntax is similar and yet different: 
 
 
Syntax
type parameter bound TypeParameter extends Class & Interface 1 & ... & Interface N
wildcard bound
upper bound
lower bound
? extends SuperType
? super   SubType

A wildcard can have only one bound, either  a lower or an upper bound.  A list of wildcard bounds is not permitted. 

A type parameter, in constrast, can have several bounds, but there is no such thing as a lower bound for a type parameter. 

LINK TO THIS TypeArguments.FAQ203
REFERENCES What is a wildcard?
What is a wildcard bound?
What is a type parameter?
What is a type parameter bound?
Why is there no lower bound for type parameters?



CONTENT PREVIOUS NEXT INDEX
  © Copyright 1995-2022 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/GenericsFAQ/FAQSections/TypeArguments.html  last update: 13 May 2021