|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
HOME
| COURSES
| TALKS
| ARTICLES
| GENERICS
| 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.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Generic And Parameterized Types© Copyright 2004-2022 by Angelika Langer. All Rights Reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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> {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> {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? |
| 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? |
| 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):
private X first; private Y second;
public Pair(X a1, Y a2) {
Example (of a concrete parameterized type): public void printPair( Pair<String,Long> pair) {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) {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? |
| 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());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? |
| 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:
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() {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? |
| 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? |
| 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? |
| 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? |
| 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) {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) {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? |
| 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:
|
|
| 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]; // fineIn 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];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]; // illegalIf 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]; // illegalThe 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; // fineThe 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> { ... }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) {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) {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? |
| 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() {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:
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() {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() {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() {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? |
| 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): 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? |
| 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 {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? |
| 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> {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 {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> {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? |
| 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>();Counter Example: List<? extends Number> list = new ArrayList<String>(); // errorType 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? |
| 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): 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? |
| 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? |
| 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> {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 {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> {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):
|
|
| 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>();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();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]; // illegalThe 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; // fineThe 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> { ... }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];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] ; // fineThe 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<?,?>[] arrThe 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> {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 <?> { // errorThe 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> { // fineNote 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 |
|
| 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? |