|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
HOME
| COURSES
| TALKS
| ARTICLES
| GENERICS
| LAMBDAS
| IOSTREAMS
| ABOUT
| CONTACT
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Java Generics FAQs - Type Parameters
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
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.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Type Parameters© Copyright 2004-2022 by Angelika Langer. All Rights Reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A place holder for a type argument. | |
|
Generic types have one or more type parameters.
Example of a parameterized type: interface Comparable<E> {The identifier E is a type parameter. Each type parameter is replaced by a type argument when an instantiation of the generic type, such as Comparable<Object> or Comparable<? extends Number> , is used. |
|
| LINK TO THIS | TypeParameters.FAQ001 |
| REFERENCES |
How
is a generic type defined?
What is a bounded type parameter? Where is a type parameter visible (or invisible)? |
| A type parameter with one or more bounds. The bounds restrict the set of types that can be used as type arguments and give access to the methods defined by the bounds. | |
|
When you declare a type parameter
T
and use it
in the implementation of a generic type or method, the type parameter
T
still denotes an unknown type. The compiler knows that
T
is a place holder for a type, but it does not know anything about the type.
This is okay in some implementations, but insufficient in others.
Example (of a generic type without bounds): public class Hashtable<Key,Data> {The implementation of class Hashtable invokes the methods hashCode and equals on the unknown Key type. Since hashCode and equals are methods defined in class Object and available for all reference types, not much need to be known about the unknown Key type. This changes substantially, when we look into the implementation of sorted sequence. Example (of a generic type, so far without bounds): public interface Comparable<T> {The implementation of class TreeMap invokes the method compareTo on the unknown Key type. Since compareTo is not defined for arbitrary types the compiler refuses to invoke the compareTo method on the unknown type Key because it does not know whether the key type has a compareTo method. In order to allow the invocation of the compareTo method we must tell the compiler that the unknown Key type has a compareTo method. We can do so by saying that the Key type implements the Comparable<Key> interface. We can say so by declaring the type parameter Key as a bounded parameter. Example (of the same generic type, this time with bounds): public interface Comparable<T> {In the example above, the type parameter Key has the bound Comparable<Key> . Specification of a bound has two effects:
|
|
| LINK TO THIS | TypeParameters.FAQ002 |
| REFERENCES |
When
would I use a wildcard parameterized with a lower bound?
What is a type parameter bound? Which types are permitted as type parameter bounds? Can I use different instantiations of a same generic type as bounds of a type parameteer? Does a bound that is a class type give access to all its public members? Can I use a type parameter as part of its own bounds or in the declaration of other type parameters? |
| A reference type that is used to further describe a type parameter. It restricts the set of types that can be used as type arguments and gives access to the non-static methods that it defines. | |
|
A type parameter can be unbounded. In this case any
reference type can be used as type argument to replace the unbounded type
parameter in an instantiation of a generic type.
Alternatively can have one or several bounds. In this case the type argument that replaces the bounded type parameter in an instantiation of a generic type must be a subtype of all bounds. The syntax for specification of type parameter bounds is: <TypeParameter extends Class & Interface 1 & ... & Interface N >A list of bounds consists of one class and/or several interfaces. Example (of type parameters with several bounds): class Pair<A extends Comparable<A> & Cloneable ,This is a generic class with two type arguments A and B , both of which have two bounds. |
|
| LINK TO THIS | TypeParameters.FAQ101 |
| REFERENCES |
What
is the difference between a wildcard bound and a type parameter bound?
Which types are permitted as type parameter bounds? Can I use different instantiations of a same generic type as bounds of a type parameteer? |
| All classes, interfaces and enum types including parameterized types, but no primitive types and no array types. | |
|
All classes, interfaces, and enum types can be used as
type parameter bound, including nested and inner types. Neither primitive
types nor array types be used as type parameter bound.
Examples (of type parameter bounds): class X0 <T extends int > { ... } // errorThe code sample shows that primitive types such as int and array types such as Object[] are not permitted as type parameter bound. Class types, such as Number or String , and interface types, such as Runnable , are permitted as type parameter bound. Enum types, such as Thread.State are also permitted as type parameter bound. Thread.State is an example of a nested type used as type parameter bound. Non-static inner types are also permitted. Raw types are permitted as type parameter bound; List is an example. Parameterized types are permitted as type parameter bound, including concrete parameterized types such as List<String> , bounded wildcard parameterized types such as List<? extends Number> and Comparable<? super Long> , and unbounded wildcard parameterized types such as Map.Entry<?,?> . A bound that is a wildcard parameterized type allows as type argument all types that belong to the type family that the wildcard denotes. The wildcard parameterized type bound gives only restricted access to fields and methods; the restrictions depend on the kind of wildcard. Example (of wildcard parameterized type as type parameter bound): class X< T extends List<? extends Number> > {Reference variables of type T (the type parameter) are treated like reference variables of a wildcard type (the type parameter bound). In our example the consequence is that the compiler rejects invocation of methods that take an argument of the "unknown" type that the type parameter stands for, such as List.add , because the bound is a wildcard parameterized type with an upper bound. At the same time the bound List<? extends Number> determines the types that can be used as type arguments. The compiler accepts all type arguments that belong to the type family List<? extends Number> , that is, all subtypes of List with a type argument that is a subtype of Number . Note, that even types that do not have subtypes, such as final classes and enum types, can be used as upper bound. In this case there is only one type that can be used as type argument, namely the type parameter bound itself. Basically, the parameterization is pointless then. Example (of nonsensical parameterization): class Box< T extends String > {The compiler rejects all type arguments except String as "not being within bounds". The type parameter T is not needed and the Box class would better be defined as a non-parameterized class. |
|
| LINK TO THIS | TypeParameters.FAQ102 |
| REFERENCES |
What
is a type parameter bound?
Can I use a type parameter as a type parameter bound? Can I use different instantiations of a same generic type as bounds of a type parameter? Can I use a type parameter as part of its own bounds or in the declaration of other type parameters? How do unbounded wildcard instantiations of a generic type relate to other instantiations of the same generic type? How do wildcard instantiations with an upper bound relate to other instantiations of the same generic type? How do wildcard instantiations with a lower bound relate to other instantiations of the same generic type? Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type? |
| Yes. | |
|
A type parameter can be used as the bound of another type
parameter.
Example (of a type parameter used as a type parameter bound): class Triple <T> {In this example the type parameter T of the parameterized class is used as bound of the type parameters U , V and W of a parameterized instance method of that class. Further opportunities for using type parameters as bounds of other type parameters include situations where a nested type is defined inside a generic type or a local class is defined inside a generic method. It is even permitted to use a type parameter as bound of another type parameter in the same type parameter section. |
|
| LINK TO THIS | TypeParameters.FAQ102A |
| REFERENCES |
Can
I use a type parameter as part of its own bounds or in the declaration
of other type parameters?
Which types are permitted as type parameter bounds? Where is a type parameter visible (or invisible)? Can I use different instantiations of a same generic type as bounds of a type parameteer? What is the difference between a wildcard bound and a type parameter bound? |
Can
I use different instantiations of a same generic type as bounds of a type
parameter?
| No, at most one instantiation of the same generic type can appear in the list of bounds of a type parameter. | |
Example (of illegal use of two instantiations of the same
generic type as bounds of a type parameter):
In the example the type parameter T is required to be Comparable<T> , that is, comparable to its own type. This is needed for storing objects of type T in a TreeSet<T> . At the same time the type parameter T is required to be Comparable<String> , because we want to invoke the type parameter's compareTo(String) method. Remember, type parameter bounds are needed to give the compiler access to the type parameters non-static methods. In this (admittedly contrived) example, we need to specify two instantiations of the Comparable interface as bound of the type parameter, but the compiler rejects it. The reason for this restriction is that there is no type that is a subtype of two different instantiations of the Comparable interface and could serve as a type argument. It is prohibited that a type implements or extends two different instantiations of the same interface. This is because the bridge method generation process cannot handle this situation. Details are discussed in a separate FAQ entry (click here ). If no class can ever implement both instantiations of Comparable , there is no point to a bounds list that requires it. The class in our example would not be instantiable because no type can ever be within bounds, except perhaps class String . In practice, you will need to work around this restriction. Sadly, there might be situations in which there is no workaround at all. |
|
| LINK TO THIS | TypeParameters.FAQ103 |
| REFERENCES |
Can
a class implement different instantiations of the same generic interface?
What is type erasure? What is a bridge method? How does type erasure work when a type parameter has several bounds? How can work around the restriction that a type parameter cannot have different instantiations of a same generic type as its bounds? |
How
can I work around the restriction that a type parameter cannot have different
instantiations of a same generic type as its bounds?
| Usually there is no satisfactory workaround. | |
|
Let us use the example from the previous question for our
search of a workaround.
Example (of illegal use of two instantiations of the same generic type as bounds of a type parameter): class ObjectStore<T extends Comparable<T> & Comparable<String> > { // errorIn the example the type parameter T is required to be Comparable<T> , because objects of type T are stored in a TreeSet<T> . At the same time the type parameter T is required to be Comparable<String> , because we invoke the type parameter's compareTo(String) method. The compiler rejects the attempt of specifying two instantiations of the Comparable interface as bound of the type parameter. One workaround for the example above could be the following: we could drop the requirement that the parameter T must be Comparable<T> , because the corresponding compareTo(T) method is not invoked in the implementation of the generic class itself, but in the operations of the Treeset<T> . By dropping the requirement we would risk that a type argument is supplied that is not Comparable<T> and will cause ClassCastException s when operations of the TreeSet<T> are invoked. Clearly not a desirable solution, but perhaps a viable one for this particular example. However, this might not be a solution if the class uses the type parameter in a slightly different way. For instance, if both compareTo methods were called in the implementation of the generic class, then we could not drop any of the bounds. Example (another class with illegal use of two instantiations of the same generic type as bounds of a type parameter): class SomeClass<T extends Comparable<T> & Comparable<String> > { // errorIf the methods of the bounds are invoked in the class implementation, then dropping one of the conflicting bounds does not solve the problem. One could consider use of an additional interface, such as a CombinedComparable interface that combines the two required interfaces into one interface. Example (conceivable work-around; does not work): interface CombinedComparable<T> {However, this is not really a viable solution, because it excludes class String as a type argument. String is a class that is comparable to itself and to String , but it is does not implement a CombinedComparable interface. Hence type String is not within bounds. Another conceivable alternative is definition of one new interface per instantiation needed, such as a parameterized SelfComparable and a non-parameterized StringComparable interface. Again, this excludes class String as a potential type argument. If it acceptable that class String is excluded as a potential type argument then the definition of additional interfaces might be a viable workaround. But there remain some situations, in which additional interfaces do not help. For instance, if the type parameter is used as type argument of another parameterized method, then it must itself be within the bounds of that other type parameter. Example (another class with illegal use of two instantiations of the same generic type as bounds of a type parameter): No solution sketched out above would address this situation appropriately. If we required that the type parameter be CombinedComparable , it would not be within the bounds of at least one of the two invoked methods. Note, that the CombinedComparable interface can be a subinterface of only one of the two instantiations of Comparable , but not both. Example (conceivable work-around; does not work): interface CombinedComparable<T> extends Comparable<String> {The same happens when we require that the type parameter be SelfComparable and StringComparable . Even if both were subinterfaces of the respective instantiation of Comparable , there cannot be a class that implements both, because that class would indirectly implement the two instantiations of Comparable . Ultimately the realization is that, depending on the circumstances, there might not be a work around at all. |
|
| LINK TO THIS | TypeParameters.FAQ104 |
| REFERENCES |
Can
I use different instantiations of a same generic type as bounds of a type
parameter?
Can a class implement different instantiations of the same parameterized interface? |
| Yes, except any constructors. | |
|
A bound that is a class gives access to all its public
members, that is, public fields, methods, and nested type. Only constructors
are not made accessible, because there is no guarantee that a subclass
of the bound has the same constructors as the bound.
Example (of a class used as bound of a type parameter): public class SuperClass {The bound SuperClass gives access to its nested types, static fields and methods and non-static fields and methods. Only the constructor is not accessible. This is because constructors are not inherited. Every subclass defines its own constructors and need not support its superclass's constructors. Hence there is no guarantee that a subclass of SuperClass will have the same constructor as its superclass. Although a superclass bound gives access to types, fields and methods of the type parameter, only the non-static methods are dynamically dispatched. In the unlikely case that a subclass redefines types, fields and static methods of its superclass, these redefinitions would not be accessible through the superclass bound. Example (of a subclass of the bound used for instantiation):
Calling the nonStaticMethod results in invocation of the subclass's overriding version of the nonStaticMethod . In contrast, the subclass's redefinitions of types, fields and static methods are not accessible through the bounded parameter. This is nothing unusual. First, it is poor programming style to redefine in a subclass any of the superclass's nested types, fields and static methods. Only non-static methods are overridden. Second, the kind of hiding that we observe in the example above also happens when a subclass object is used through a superclass reference variable. |
|
| LINK TO THIS | TypeParameters.FAQ105 |
| REFERENCES | |
| As a type that can only be instantiation for its subtypes, and those subtypes will inherit some useful methods, some of which take subtype arguments (or otherwise depend on the subtype). | |
The context in which
"
Enum<E extends
Enum<E>>
"
appears is the declaration of the
Enum
class in package
java.lang
:
public abstract class Enum<E extends Enum<E>> {The type Enum is the common base class of all enumeration types. In Java an enumeration type such as Color is translated into a class Color that extends Enum<Color> . The purpose of the superclass Enum is to provide functionality that is common to all enumeration types. Here is a sketch of class Enum : public abstract class Enum< E extends Enum<E>> implements Comparable< E >, Serializable {The surprising feature in the declaration " Enum<E extends Enum<E>> " is the fact that the newly defined class Enum and its newly defined type parameter E appear in the bound of that same type parameter. It means that the Enum type must be instantiated for one of its subtypes. In order to understand why this makes sense, consider that every enum type is translated into a subtype of Enum . Here is the contrived enum type Color : enum Color {RED, BLUE, GREEN}The compiler translates it into the following class: public final class Color extends Enum<Color> {The inheritance has the effect that the Color type inherits all the methods implemented in Enum<Color> . Among them is the compareTo method. The Color.compareTo method should probably take a Color as an argument. In order to make this happen class Enum is generic and the Enum.compareTo method takes Enum 's type parameter E as an argument. As a result, type Color derived from Enum<Color> inherits a compareTo method that takes a Color as and argument, exactly as it should. If we dissect the declaration " Enum<E extends Enum<E>> " we can see that this pattern has several aspects. First, there is the fact that the type parameter bound is the type itself: " Enum <E extends Enum <E>> ". It makes sure that only subtypes of type Enum are permitted as type arguments. (Theoretically, type Enum could be instantiated on itself, like in Enum<Enum> , but this is certainly not intended and it is hard to imagine a situation in which such an instantiation would be useful.) Second, there is the fact that the type parameter bound is the parameterized type Enum <E> , which uses the type parameter E as the type argument of the bound. This declaration makes sure that the inheritance relationship between a subtype and an instantiation of Enum is of the form " X extends Enum<X> ". A subtype such as " X extends Enum<Y> " cannot be declared because the type argument Y would not be within bounds; only subtypes of Enum<X> are within bounds. Third, there is the fact that Enum is generic in the first place. It means that some of the methods of class Enum take an argument or return a value of an unknown type (or otherwise depend on an unknown type). As we already know, this unknown type will later be a subtype X of Enum<X> . Hence, in the parameterized type Enum<X> , these methods involve the subtype X , and they are inherited into the subtype X . The compareTo method is an example of such a method; it is inherited from the superclass into each subclass and has a subclass specific signature in each case.
To sum it up, the declaration
"
Enum<E extends Enum<E>>
"
can be decyphered as:
Enum
is a generic type that can only be
instantiated for its subtypes, and those subtypes will inherit some useful
methods, some of which take subtype specific arguments (or otherwise depend
on the subtype).
|
|
| LINK TO THIS | TypeParameters.FAQ106 |
| REFERENCES |
How
is a generic type defined?
What is a bounded type parameter? Where is a type parameter visible (or invisible)? |
| Because it does not make sense for type parameters of classes; it would occasionally be useful in conjunction with method declarations, though. | |
|
Type parameters can have several upper bounds, but no lower
bound. This is mainly because lower bound type parameters of classes
would be confusing and not particularly helpful. In conjunctions
with method declarations, type parameters with a lower bound would occasionally
be useful. In the following, we first discuss lower bound type parameters
of
classes
and subsequently
lower bound type parameters of
methods
.
Lower Bound Type Parameters of Classes Type parameters can have several bounds, like in class Box<T extends Number> {...} . But a type parameter can have no lower bound, that is, a construct such as class Box<T super Number> {...} is not permitted. Why not? The answer is: it is pointless because it would not buy you anything, were it allowed. Let us see why lower bound type parameters of classes are confusing by exploring what a upper bound on a type parameter means. The upper bound on a type parameter has three effects:
Example (of restricted instantiation due to an upper bound on a type
parameter):
private T value; public Box(T t) { value = t; } ... }
public static void main(String[] args) { Box<Long> boxOfLong = new Box<Long>(0L); // fine Box<String> boxOfString = new Box<String>(""); // error: String is not within bounds } }
private T value; public Box(T t) { value = t; } public int increment() { return value.intValue()+1; } // <= would be an error without the Number bound ... }
Example (of use of upper bound on a type parameter in type erasure -
before
type erasure):
private T value; public Box( T t) { value = t; } ... }
private Number value; public Box( Number t) { value = t; } ... }
Restricted Instantiations. The compiler could restrict the set of types that can be used for instantiation of the generic type with a lower bound type parameter. For instance, the compiler could permit instantiations such as Box<Number> and Box<Object> from a Box<T super Number> and reject instantiations such as Box<Long> or Box<Short> . This would be an effect in line with the restrictive side-effect described for upper type parameter bounds. Access To Non-Static Members. A lower type parameter bound does not give access to any particular methods beyond those inherited from class Object . In the example of Box<T super Number> the supertypes of Number have nothing in common, except that they are reference types and therefore subtypes of Object . The compiler cannot assume that the field of type T is of type Number or a subtype thereof. Instead, the field of type T can be of any supertype of Number , such as Serializable or Object . The invocation of a method such as intValue() is no longer type-safe and the compiler would have to reject it. As a consequence, the lower type parameter bound would not give access to an non-static members beyond those defined in class Object and thus has the same effect as "no bound". Type Erasure . Following this line of logic, it does not make sense to replace the occurences of the type parameter by its leftmost lower bound. Declaring a method like the constructor Box( T t) as a constructor Box( Number t) does not make sense, considering that T is replaces by a supertype of Number . An Object might be rightly passed to the constructor in an instantiation Box<Object> and the constructor would reject it. This would be dead wrong. So, type erasure would replace all occurences of the type variable T by type Object , and not by its lower bound. Again, the lower bound would have the same effect as "no bound". Do you want to figure out what it would mean if both lower _and_ upper bounds were permitted? Personally, I do not even want to think about it and would prefer to file it under "not manageable", if you permit. The bottom line is: all that a " super " bound would buy you is the restriction that only supertypes of Number can be used as type arguments. And even that is frequently misunderstood. It would NOT mean, that class Box<T super Number> {...} contains only instances of supertypes of Number . Quite the converse - as the example below demonstrates! Example (of use of upper bound on a type parameter in type erasure - before type erasure): class Box< T super Number > { class Box {
Lower Bound Type Parameters of Methods In conjunction with methods and their argument types, a type parameter with a lower bound can occasionally be useful. Example (of a method that would profit from a type parameter with a lower bound): class Pair<X,Y> {The addToMap() method adds the content of the pair to a map. Any map that can hold supertypes of X and Y would do. The map's put() method returns the value found in the map for the given key, if there already is a key-value entry for the key in the map. The return value of the map's put() method shall be returned from the addToMap() method. Under these circumstances one would like to declare the method as shown above: The map is parameterized with supertypes of the pair's type parameters and the addToMap() method'S return type is the map's value type. Since the compiler does not permit lower bounds on type parameters we need a work-around. One work-around that comes to mind is use of a wildcard, because wildcards can have a lower bound. Here is a work-around using a wildcard. Example (of a work-around for the previous example using wildcards): class Pair<X,Y> {It works, except that there is no way to declare the return type as desired. It would be the supertype of Y that the compiler captures from the map type, but there is no syntax for specifying it. We must not declare the return type a " ? super Y ", because " ? super Y " is a wildcard and not a type and therefore not permitted as a return type. We have no choice and must use Object instead as our method's return type. This rather unspecific return type in turn forces callers of the addToMap() method into casting the return value down from Object to its actual type. This is not exactly what we had in mind. Another work-around is use of static methods. Here is a work-around with a static instead of a non-static method. Example (of a work-around for the previous example using a static method): class Pair<X,Y> {The generic addToMap() method has four type parameters: two placeholders X and Y for the pair's type and two placeholders A and B for the map's type. A and B are supertypes of X and Y , because X and Y are declared with A and B as their upper bounds. (Note, that the generic method's type parameters X and Y have nothing to do with the Pair class's X and Y parameters. The names X and Y are reused for the generic method to make them easily recognizably as the pair's type parameters.) Using four type parameters we can declare the precise return type as desired: it is the same type as the value type of the map.
The bottom line is that the usefulness of lower bounds on type parameters is somewhat debatable. They would be confusing and perhaps even misleading when used as type parameters of a generic class. On the other hand, generic methods would occasionally profit from a type parameter with a lower bound. For methods, a work-around for the lack of a lower bound type parameter can often be found. Such a work-around typically involves a static generic method or a lower bound wildcard. |
|
| LINK TO THIS | TypeParameters.FAQ107 |
| REFERENCES |
What
is a bounded type parameter?
Does a bound that is a class type give access to all its public members? What is a bounded wildcard? What is the difference between a wildcard bound and a type parameter bound? |
| No, a type parameter is not a type in the regular sense (different from a regular type such as a non-generic class or interface). | |
Type parameters can be used for typing (like non-generic
classes and interfaces)::
|
|
| LINK TO THIS | TypeParameters.FAQ200 |
| REFERENCES | |
| No, because the compiler does not know how to create objects of an unknown type. | |
|
Each object creation is accompied by a constructor call.
When we try to create an object whose type is a type parameter then we
need an accessible constructor of the unknown type that the type parameter
is a place holder for. However, there is no way to make sure that
the actual type arguments have the required constructors.
Example (illegal generic object creation): public final class Pair< A , B > {In the example above, we are trying to invoke the no-argument constructors of two unknown types represented by the type parameters A and B . It is not known whether the actual type arguments will have an accessible no-argument constructor. In situations like this - when the compiler needs more knowledge about the unknown type in order to invoke a method - we use type parameter bounds. However, the bounds only give access to methods of the type parameter. Constructors cannot be made available through a type parameter bound. If you need to create objects of unknown type, you can use reflection as a workaround. It requires that you supply type information, typically in form of a Class object, and then use that type information to create objects via reflection. Example (workaround using reflection): public final class Pair <A,B> { |
|
| LINK TO THIS | TypeParameters.FAQ201 |
| REFERENCES |
Does
a bound that is a class type give access to all its methods and fields?
How do I generically create objects and arrays? How do I pass type information to a method so that it can be used at runtime? |
| No, because the compiler does not know how to create an object of an unknown component type. | |
|
We can declare array variables whose component type is
a type parameter, but we cannot create the corresponding array objects.
The compiler does not know how to create an array of an unknown component
type.
Example (before type erasure): class Sequence <T> {Example (after a conceivable translation by type erasure): class Sequence {The type erasure of a type parameter is its leftmost bound, or type Object if no bound was specified. As a result, the compiler would create an array of Object s in our example. This is not what we want. If we later invoked the as Array method on a Sequence<String> a Object[] would be returned, which is incompatible to the String[] that we expect. Example (invocation of illegal method): Not even a ca st would help because the cast is guaranteed to fail at runtime. The returned array is really an array of Object s, not just a reference of type Object[] refering to a String[] . If you need to create arrays of an unknown component type, you can use reflection as a workaround. It requires that you supply type information, typically in form of a Class object, and then use that type information to create arrays via reflection. Example (workaround using reflection): class Sequence <T> {By the way, the unchecked warning is harmless and can be ignored. It stems from the need to cast to the unknown array type, because the newInstance method returns an Object[] as a result. |
|
| LINK TO THIS | TypeParameters.FAQ202 |
| REFERENCES |
What
is type erasure?
How do I generically create objects and arrays? How do I pass type information to a method so that it can be used at runtime? |
| Yes, you can, but it is not type-safe and the compiler issues an "unchecked" warning. | |
|
Type parameters do not have a runtime type representation
of their own. They are represented by their leftmost bound, or type
Object
in case of an unbounded type parameter. A cast to a type parameter would
therefore be a cast to the bound or to type
Object
.
Example (of unchecked cast): The two casts to the type parameters are pointless because they will never fail; at runtime they are casts to type Object . As a result any type of |
|
| LINK TO THIS | TypeParameters.FAQ203 |
| REFERENCES |
What
does type-safety mean?
What is type erasure? What is the type erasure of a type parameter? |
| It depends. | |
| Type parameters can appear in throws clauses, but not in catch clauses. | |
| LINK TO THIS | TypeParameters.FAQ204 |
| REFERENCES |
Can
I use a type parameter in a catch clause?
Can I use a type parameter in in a throws clause? Can I throw an object whose type is a type parameter? |
| No, because a type parameter does not have a runtime type representation of it own. | |
|
As part of the translation by type erasure, all type
parameters are replaces by their leftmost bound, or
Object
if
the type parameter is unbounded. Consequently, there is no point
to deriving from a type parameter, because we would be deriving from its
bound, not from the type that the type parameter stands for. In addition,
the actual type argument can be a final class or an enum type, from which
we must not derive anyway.
Example (of illegal derivation from type parameter; before type erasure): class Printable<T extends Collection<?>> extends T { // illegalThe idea of this generic subclass is that it adds print functionality to all collection classes by means of derivation. A Printable<LinkedList<String>> would have all the functionality of LinkedList<String> plus the print functionality. (This idiom is known in C++ as the curiously recurring template pattern ). Since it is illegal to derive from a type parameter, this kind of programming technique is not possible in Java. Consider what the subclass would look like after type erasure. Example (same example after a conceivable translation by type erasure): class Printable extends Collection { // error: Collection is an interface, not classAfter type erasure the subclass Printable would not be a subclass of LinkedList , but a subclass of Collection , which is not even possible, because Collection is an interface, not a class. Even if we used a class as the bound of the type parameter, such as <T extends AbstractCollection> , none of the list-specific methods would be available in the subclass, which entirely defeats the purpose of this programming pattern. |
|
| LINK TO THIS | TypeParameters.FAQ205 |
| REFERENCES |
What
is type erasure?
Which types are permitted as type arguments? The Curiously Recurring Template Pattern in C++ (James O. Coplien. A Curiously Recurring Template Pattern. In C++ Gems, 135-144. Cambridge University Press, New York, 1996) |
Why
is there no class literal for a type parameter?
| Because a type parameter does not have a runtime type representation of its own. | |
|
As part of the translation by type erasure, all type
parameters are replaces by their leftmost bound, or
Object
if
the type parameter is unbounded. Consequently, there is no point
to forming class literals such as
T.class
, where
T
is
a type parameter, because no such
Class
objects exist. Only
the bound has a
Class object
that represents its runtime type.
Example (before type erasure): <T extends Collection> Class<?> someMethod(T arg){The compiler rejects the expression T.class as illegal, but even if it compiled it would not make sense. After type erasure the method above could at best look like this: Example (after type erasure): Class someMethod( Collection arg){The method would always return the bound's type representation, no matter which instantiation of the generic method was invoked. This would clearly be misleading. The point is that type parameters are non-reifiable , that is, they do not have a runtime type representation. Consequently, there is no Class object for type parameters and no class literal for them. |
|
| LINK TO THIS | TypeParameters.FAQ206 |
| REFERENCES |
What
is type erasure?
What is a reifiable type? |
| Everywhere in the definition of a generic type or method, except any static context of a type. | |
|
Generic Classes
The scope of a class's type parameter is the entire definition of the class, except any static members or static initializers of the class. This means that the type parameters cannot be used in the declaration of static fields or methods or in static nested types or static initializers. Example (of illegal use of type parameter in static context of a generic class): class SomeClass <T> {The example illustrates that the type parameter cannot be used in the static context of a generic class. It also shows that nested interfaces and enum types are considered static type members of the class. Only inner classes, that is, non-static nested classes, can use the type parameter of the enclosing generic class. Generic Interfaces The scope of an interface's type parameter is the entire definition of the interface, except any fields or nested types. This is because fields and nested types defined in an interface are implicitly static. Example (of illegal use of type parameter in a generic interface): interface SomeInterface <T> {The example shows that fields of an interface are implicitly static, so that the type parameter cannot be used anywhere in the declaration of a field of a generic interface. Similarly, the nested class is considered a static nested class, not an inner class, and for this reason use of the type parameter anywhere in the nested class is illegal. Generic Methods The scope of a method's or constructor's type parameter is the entire definition of the method; there is no exception, because a method has no static parts. Example (of use of type parameter in a generic method): private interface Copyable<T> {The example illustrates that the type parameter can be used any place in the definition of a generic method. The type parameter can appear in the return and argument type. It can appear in the method body and also in local (or anonymous) classes defined inside the method. Note, that it does not matter whether the generic method itself is static or non-static. Methods, different from types, do not have any "static context"; there is no such thing as a static local variable or static local class. |
|
| LINK TO THIS | TypeParameters.FAQ301 |
| REFERENCES |
Why
can't I use a type parameter in any static context of the generic class?
Can I use a type parameter as part of its own bounds or in the declaration of other type parameters? |
| Yes, the scope of a type parameter includes the type parameter section itself. | |
|
The type parameters of a generic type or method are visible
in the entire declaration of the type or method, including the type parameter
section itself. Therefore, type parameters can appear as parts of their
own bounds, or as bounds of other type parameters declared in the same
section.
Example (of use of a type parameter in the type parameter section itself): public final class Wrapper < T extends Comparable < T >> implements Comparable<Wrapper<T>> {In the example above, the type parameter T is used as type argument of its own bound Comparable<T> . Example (of use of a type parameter in the type parameter section itself): < S ,T extends S > T create(S arg) { ... }In the example above, the first type parameter S is used as bound of the second type parameter T . Forward references to type parameters are not permitted. The type parameter cannot be used in the entire type parameter section, but only after its point of declaration. Example (of an illegal forward reference to a type parameter): < S extends T , T extends Comparable< S >> T create(S arg) { ... } // errorIn the example above, the type parameter T is used in the type parameter section before it has been defined in the same type parameter section. This kind of forward reference is illegal. Forward references to types, not type parameters, are permitted, though. Example (of an forward reference to a type): interface Edge <N extends Node <? extends Edge<N>>> {In the example above, the type Node is used (in the type parameter section of type Edge ) before it has been defined (probably in a different source file). This kind of forward reference this permitted, which is not surprising. It is the usual way of defining and using types in Java. |
|
| LINK TO THIS | TypeParameters.FAQ302 |
| REFERENCES |
Where
is a type parameter visible (or invisible)?
Can I use the type parameter of an outer type as part of the bounds of the type parameter of an inner type or a method? |
Can
I use the type parameter of an outer type as part of the bounds of the
type parameter of an inner type or a method?
| Yes, the type parameter of an enclosing generic type or method can be used in the type parameter section of an inner generic type or method. | |
|
The type parameters of a generic type or method can appear
as parts of the bounds of the type parameters of any generic type or methods
in that scope.
Example (of use of type parameter of enclosing class in the type parameter section of a method): public final class Wrapper <T > {In the example above, the type parameter T of the class Wrapper<T> is used as bound of the type paramter U of the class's generic constructor. In principle, you can use the type parameters of a generic class anywhere in the class scope, including the type parameter sections of any generic methods or nested and inner types. For instance, the type parameters can appear in the type parameter declaration of an inner class. Example (of use of type parameter of enclosing class in the type parameter section of an inner class): public final class Wrapper <T> {In this example, the type parameter T of the class Wrapper<T> is used as part of the bound of the type parameter W of inner class WrapperComparator . In addition, it is also used as part of the bound of the type parameter V of the comparator method. Similar rules apply to generic interfaces. Even the type parameters of a generic method can be used in the declaration of the type parameters of a local generic type. Example (of use of type parameter of a method in the type parameter section of a local class): class Test {However, generic local classes are rather rare in practice. The type parameters of a generic type or method can appear anywhere in the declaration of the type parameters of any generic type or methods in that scope. A type parameter T can appear
Example (of illegal use of type parameter as a bound):: class Wrapper<T> implements Cloneable {The type parameter T is followed by another bound, which is illegal. |
|
| LINK TO THIS | TypeParameters.FAQ303 |
| REFERENCES |
Where
is a type parameter visible (or invisible)?
Can I use a type parameter as part of its own bounds? |
| No, there is only one instance of a static field for all instantiations of a generic type. | |
|
If a generic type has a static field, how many instances
of this static field exist?
Example (of a generic class with a static field): class SomeClass<T> {The generic type can be instantiated for an arbitrary number of type arguments. Is there a different instance of the static field for each instantiation of the generic type? Example (of several instantiations and usage of the static field(s)): SomeClass<String> ref1 = new SomeClass<String>();The question is: are we accessing two different static fields in the code snippet above? The answer is: no, there is only one instance of a static field per parameterized type, not several ones per instantiation of the generic type. The reason is that the compiler translates the definition of a generic type into one unique byte code representation of that type. The different instantiations of the generic type are later mapped to this unique representation by means of type erasure . The consequence is that there is only one static count field in our example, despite of the fact that we can work with as many instantiations of the generic class as we like. Example (showing the syntax for access to a static field of a generic type): SomeClass<String> ref1 = new SomeClass<String>();Although we can refer to the static field through reference variables of different type, namely of type SomeClass<String> and SomeClass<Long> in the example, we access the same unique static count field. The uniqueness of the static field is more clearly expressed when we refer to the static field using the enclosing scope instead of object references. Saying SomeClass.count makes clear that there is only one static count field that is independent of the type parameters of the enclosing class scope. Since the static field is independent of the enclosing class's type parmeters it is illegal to use any instantiation of the generic enclosing class as scope qualifier. |
|
| LINK TO THIS | TypeParameters.FAQ401 |
| REFERENCES |
What
is type erasure?
How do I refer to static members of a parameterized type? Where is a type parameter visible (or invisible)? Why can't I use a type parameter in any static context of the generic class? |
Why
can't I use a type parameter in any static context of a generic class?
| Because the static context is independent of the type parameters and exists only once per raw type, that is, only once for all instantiations of a generic type. | |
|
Type parameters must not appear in any static context of
a generic type, which means that type parameters cannot be used in the
declaration of static fields or methods or in static nested types or static
initializers.
Example (of illegal use of a type parameter in static context): public final class X <T> {The attempt of declaring a static field of the unknown type T is non-sensical and rightly rejected by the compiler. There is only one instance of the static field for all instantiations of the generic class. Of which type could that static field possibly be? The declaration of a static field, whose type is the type parameter, makes it look like there were several instances of different types, namely one per instantiation, which is misleading and confusing. For this reason, the use of type parameters for declaration of static fields is illegal. As static methods often operate on static fields it makes sense to extend the rule to static methods: the type parameter must not appear in a static method. Interestingly, the same rule applies to static nested types defined in a generic class. There is no compelling technical reason for this restriction. It's just that static nested types are considered independent of any instantiations of the generic class, like the static fields and methods. For this reason, use of the type parameter in a static nested type is illegal. (Note, static nested types include nested static classes, nested interfaces and nested enum types.) Example (of illegal use of a type parameter in static context): class Wrapper <T> { public Wrapper( T t) { theObject = t; }In the example above the type parameter is used in the context of a nested class type. The compiler rejects the use of the type parameter because the class type is a nested static class.
Workaround for nested static classes and interfaces: In case of static nested classes and interfaces this is not a major calamity. As a workaround we can generify the static class or interface itself. Example (workaround - generify the nested static type): class Wrapper <T> { public Wrapper( T t) { theObject = t; }There is no such workaround for nested enum type because they cannot be generic. Workaround for nested static classes: If the nested static type is a class, an alternative workaround would be turning the static class into an non-static inner class. Example (workaround - use an inner class): class Wrapper <T> { public Wrapper( T t) { theObject = t; }This workaround comes with a certain amount of overhead because all inner classes have a hidden reference to an instance of the outer type, which in this example they neither need nor take advantage of; the hidden reference is just baggage. Often, inner classes are combined with interfaces in order to keep the inner class a private implementation detail of the enclosing class. We can do the same here. Example (the previous workaround refined): class Wrapper <T> { public Wrapper( T t) { theObject = t; }As you can see, the nested public interfaces need to be generic whereas the inner private classes can use enclosing class's the type parameter. |
|
| LINK TO THIS | TypeParameters.FAQ402 |
| REFERENCES |
Where
is a type parameter visible (or invisible)?
Is there one instances of a static field per instantiation of a generic type? |