|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
HOME
| COURSES
| TALKS
| ARTICLES
| GENERICS
| LAMBDAS
| IOSTREAMS
| ABOUT
| CONTACT
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Java Generics FAQs - Type Arguments
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
This is a collection of answers to frequently asked questions
(FAQs) about Java Generics, a new language feature added to the Java programming
language in version 5.0 of the Java Standard Edition (J2SE 5.0).
If you want to provide feedback or have any questions regarding Java
generics, to which you cannot find an answer in this document, feel free
to send me
EMAIL
or use the
GENERICS FAQ
form.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Type Arguments© Copyright 2004-2022 by Angelika Langer. All Rights Reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A reference type that is used for the instantiation of a generic type or for the instantiation of a generic method, or a wildcard that is used for the instantiation of a generic type . An actual type argument replaces the formal type parameter used in the declaration of the generic type or method. | |
|
Generic types and methods have formal type parameters,
which are replaced by actual type arguments when the parameterized type
or method is instantiated.
Example (of a generic type): class Box <T> {In the example we see a generic class Box with one formal type parameter T. This formal type parameter is replaced by actual type argument String , when the Box type is used in the test program. There are few of rules for type arguments:
|
|
| LINK TO THIS | TypeArguments.FAQ001 |
| REFERENCES |
What
is a wildcard?
What is a type parameter? Which types are permitted as type arguments? Are primitive types permitted as type arguments? Are wildcards permitted as type arguments? Are type parameters permitted as type arguments? Do type parameter bounds restrict the set of types that can be used as type arguments? |
| All references types including parameterized types, but no primitive types. | |
|
All reference types can be used a type arguments of a parameterized
type or method. This includes classes, interfaces, enum types, nested
and inner types, and array types. Only primitive types cannot be
used as type argument.
Example (of types as type arguments of a parameterized type): List< int > l0; // errorThe code sample shows that a primitive type such as int is not permitted as type argument. Class types, such as String , and interface types, such as Runnable , are permitted as type arguments. Enum types, such as TimeUnit (see java.util.concurrent.TimeUnit ), are also permitted as type arguments. Raw types are permitted as type arguments; Comparable is an example. Thread.State is an example of a nested type; Thread.State is an enum type nested into the Thread class. Non-static inner types are also permitted. An array type, such as int[] and Object[] , is permitted as type arguments of a parameterized type or method.
Parameterized types are permitted as type arguments, including concrete
parameterized types such as
Callable<String>
, bounded
wildcard parameterized types such as
Comparable<? super Long>
and
Class<?
extends Number>
, and unbounded wildcard parameterized types such as
Map.Entry<?,?>
.
The same types are permitted as explicit type arguments of a generic method. Example (of types as type arguments of a generic method): List<?> list;The code sample shows that primitive types such as int are not permitted as type argument of a generic method either. |
|
| LINK TO THIS | TypeArguments.FAQ002 |
| REFERENCES | What is a type argument? |
| No. Only reference types can be used as type arguments. | |
|
A parameterized type such as
List<int>
or
Set<short>
is illegal. Only reference types can be used for instantiation of
generic types and methods. Instead of
List<int>
we must declare
a
List<Integer
>, using the corresponding wrapper type as the
type argument.
The lack of primitive type instantiations is not a major restriction in practice (except for performance reasons), because autoboxing and auto-unboxing hides most of the nuisance of wrapping and unwrapping primitive values into their corresponding wrapper types. Example (of autoboxing): int[] array = {1,2,3,4,5,6,7,8,9,10};Here we insert primitive type int values to the list of Integer s, relying on autoboxing, which is the automatic conversion from the primitve type to the corresponding wrapper type. Similarly, we extract primitive type int values from the list, relying on auto-unboxing, which is the automatic conversion from the wrapper type to the corresponding primitive type. Note, that the lack of primitive type instantiations incurs a performance penalty. Autoboxing and -unboxing make the use of wrapper type instantiations of generic types very convenient and concise in the source code. But the concise notation hides the fact that behind the curtain the virtual machine creates and uses lots of wrapper objects, each of which must be allocated and later garbage collected. The higher performance of direct use of primitive type values cannot be achieved with generic types. Only a regular (i.e., non-generic) type can provide the optimal performance of using primitive type values. Example: class Box <T> {The example illustrates that the instantiation of the Box type for type Long leads to the inevitable overhead of boxing and unboxing. The instantiation on the primitive type long does not help, because it is illegal. Only a dedicated non-generic BoxOfLong type eliminates the overhead by using the primitive type long . |
|
| LINK TO THIS | TypeArguments.FAQ003 |
| REFERENCES |
What
is a type argument?
Which types are permitted as type arguments? |
| For instantiation of a generic type, yes. For instantiation of a generic method, no. | |
|
A wildcard is a syntactic construct that denotes a family
of types.
All wildcards can be used as type arguments of a parameterized type. This includes the unbounded wildcard as well as wildcards with an upper or lower bound. Examples: List< ? > l0;Wildcards can not be used as type arguments of a generic method. Examples: list = Collections.< ? >emptyList(); //error |
|
| LINK TO THIS | TypeArguments.FAQ004 |
| REFERENCES |
What
is a wildcard?
What is an unbounded wildcard? What is a bounded wildcard? |
| Yes. | |
|
Type parameters of a generic type or method can be used
as arguments of parameterized types or methods.
Example (of instantiations of a generic type using a type parameter as type argument): class someClass <T> {The example above demonstrates how the type parameter T of the enclosing generic class and the type parameter S of a generic method can be used as type arguments to both a parameterized type, namely List , and a generic method, namely emptyList . |
|
| LINK TO THIS | TypeArguments.FAQ005 |
| REFERENCES |
What
is a type argument?
What is a type parameter? What is a parameterized (or generic) method? What is a parameterized (or generic) type? |
| Yes, type arguments must be within bounds. | |
|
When a formal type parameter is declared with one or several
bounds, then the actual type argument must be a subtype of all of the bounds
specified for the respective formal type parameter.
Examples: Comparable<T> uses a type parameter as its type argument. Comparable<Wrapper<T>> uses an instantiation of a parameterized type as type argument. Wrapper<String> and Wrapper<Long> have concrete reference types as type arguments. Wrapper<? extends Number> and Wrapper<?> use wildcards as type arguments. Wrapper<Number> is illegal because Number is not a subtype of Comparable<Number> and is not within bounds. Wrapper<int> is illegal because primitive types are not allowed as type arguments. |
|
| LINK TO THIS | TypeArguments.FAQ006 |
| REFERENCES |
What
is a type parameter?
What is a bounded type parameter? |
| No; you can use the so-called raw type, which is the generic type without type arguments. | |
|
A generic type without any type arguments is called a
raw
type
. Examples of raw types are
List
,
Set
,
Comparable
,
Iterable
,
etc.
Raw types are permitted for compatilibity between generic and non-generic (legacy) Java APIs. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. According to the Java Language Specification, it is possible that future versions of the Java programming language will disallow the use of raw types. |
|
| LINK TO THIS | TypeArguments.FAQ007 |
| REFERENCES |
What
is the raw type?
Can I use a raw type like any other type? How does the raw type relate to instantiations of the corresponding generic type? Where can I find a specification of the Java generics language features? |
Do
I have to specify a type argument when I want to invoke a generic method?
| No; a generic method can be used without type arguments. | |
| A generic method can be invoked like a regular method, that is, without specification of the type arguments. In such a case the compiler will automatically infer the type arguments from the static types of the method arguments or the context of the method invocation. This process is known as type argument inference . | |
| LINK TO THIS | TypeArguments.FAQ008 |
| REFERENCES |
What
is type argument inference?
What is explicit type argument specification? |
| A syntactic construct that denotes a family of types. | |
A wildcard describes a family of types. There are
3 different flavors of wildcards:
|
|
| LINK TO THIS | TypeArguments.FAQ101 |
| REFERENCES |
What
is a wildcard parameterized type?
If a wildcard appears repeatedly in a type argument section, does it stand for the same type? What is a wildcard bound? What is an unbounded wildcard? What is a bounded wildcard? Which super-subset relationships exist among wildcards? |
| A wildcard without a bound. | |
|
The unbounded wildcard looks like "
?
" and stands
for the family of
all
types.
The unbounded wildcard is used as argument for instantiations of generic types. The unbounded wildcard is useful in situations where no knowledge about the type argument of a parameterized type is needed. Example: void printCollection( Collection<?> c){ // an unbounded wildcard parameterized typeThe printCollection method does not require any particular properties of the elements contained in the collection that it prints. For this reason it declares its argument using an unbounded wildcard parameterized type, saying that any type of collection regardless of the element type is welcome. |
|
| LINK TO THIS | TypeArguments.FAQ102 |
| REFERENCES |
What
is a wildcard?
What is a wildcard parameterized type? What is an unbounded wildcard parameterized type? How do unbounded wildcard instantiations of a parameterized type relate to other instantiations of the same generic type? Which super-subset relationships exist among wildcards? |
| A wildcard with either an upper or a lower bound. | |
|
A wildcard with an upper bound looks like "
? extends
Type
" and stands for the family of all types that are subtypes of
Type
,
type
Type
being included.
Type
is called the
upper
bound
.
A wildcard with a lower bound looks like " ? super Type " and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound . Bounded wildcards are used as arguments for instantiation of generic types. Bounded wildcards are useful in situations where only partial knowledge about the type argument of a parameterized type is needed, but where unbounded wildcards carry too little type information. Example: public class Collections {The copy method copies elements from a source list into a destination list. The destination list must be capable of holding the elements from the source list. We express this by means of bounded wildcards: the output list is required to have an element type with a lower bound T and the input list must have an element type with an upper bound T . Let's study an example to explore the typical use of bounded wildcards and to explain why unbounded wildcards do not suffice. It's the example of the copy method mentioned above. It copies elements from a source list into a destination list. Let's start with a naive implementation of such a copy method. Example (of a restrictive implementation of a copy method): public class Collections {This implementation of a copy method is more restrictive than it need be, because it requires that both input and output collection must be lists with the exact same type. For instance, the following invocation - although perfectly sensible - would lead to an error message: Example (of illegal use of the copy method): List<Object> output = new ArrayList< Object >();The invocation of the copy method is rejected because the declaration of the method demands that both lists must be of the same type. Since the source list is of type List<Long> and the destination list is of type List<Object> the compiler rejects the method call, regardless of the fact that a list of Object references can hold Long s. If both list were of type List<Object> or both were of type List<Long> the method call were accepted. We could try to relax the method's requirements to the argument types and declare wildcard parameterized types as the method parameter types. Declaring wildcard parameterized types as method parameter types has the advantage of allowing a broader set of argument types. Unbounded wildcards allow the broadest conceivable argument set, because the unbounded wildcard ? stands for any type without any restrictions. Let's try using an unbounded wildcard parameterized type. The method would then look as follows: Example (of a relaxed copy method; does not compile): public class Collections {It turns out that this relaxed method signature does not compile. The problem is that the get() method of a List<?> returns a reference pointing to an object of unknown type. References pointing to objects of unknown type are usually expressed as a reference of type Object . Hence List<?>.get() returns an Object . On the other hand, the set() method of a List<?> requires something unknown, and "unknown" does not mean that the required argument is of type Object . Requiring an argument of type Object would mean accepting everything that is derived of Object . That's not what the set() method of a List<?> is asking for. Instead, "unknown" in this context means that the argument must be of a type that matches the type that the wildcard ? stands for. That's a much stronger requirement than just asking for an Object . For this reason the compiler issues an error message: get() returns an Object and set() asks for a more specific, yet unknown type. In other words, the method signature is too relaxed. Basically, a signature such as void copy( List<?> dest, List<?> src) is saying that the method takes one type of list as a source and copies the content into another - totally unrelated - type of destination list. Conceptually it would allow things like copying a list of apples into a list of oranges. That's clearly not what we want. What we really want is a signature that allows copying elements from a source list into a destination list with a specific property, namely that it is capable of holding the source list's elements. Unbounded wildcards are too relaxed for this purpose, as we've seen above, but bounded wildcards are suitable in this situation. A bounded wildcard carries more information than an unbounded wildcard. In our example of a copy method we can achieve our goal of allowing all sensible method invocations by means of bounded wildcards, as in the following implementation of the copy method: Example (of an implementation of the copy method that uses bounded wildcards): public class Collections {In this implementation we require that a type T exists that is subtype of the output list's element type and supertype of the input list's element type. We express this by means of wildcards: the output list is required to have an element type with a lower bound T and the input list must have an element type with an upper bound T . Example (of using the copy method with wildcards): List<Object> output = new ArrayList< Object >();In the first method call T would have to be a supertype of Long and a subtype of Object , and luckily there is a number of types that fall into this category, namely Number , Serializable and Comparable<Number> . Hence the compiler can use any of the 3 types as type argument and the method invocation is permitted. The second nonsensical method call is rejected by the compiler, because the compiler realizes that there is no type that is subtype of String and supertype of Long .
Conclusion
:
|
|
| LINK TO THIS | TypeArguments.FAQ103 |
| REFERENCES |
What
is a wildcard?
What is a wildcard instantiation? How do wildcard instantiations with an upper bound relate to other instantiations of the same generic type? How do wildcard instantiations with a lower bound relate to other instantiations of the same generic type? Which super-subset relationships exist among wildcards? What is a wildcard bound? Which types are permitted as wildcard bounds? What is the difference between a wildcard bound and a type parameter bound? What is the difference between a Collection<?> and a Collection<Object>? |
| It depends. | |
|
A multi-level wildcard is a wildcard that appears as the
type argument of a type argument. The instantiations
Collection<Pair<String,?>>
and
Collection<? extends Pair<String,?>>
are examples of
multi-level wildcards. Multi-level wildcard parameterized types are inherently
difficult to interpret, because the wildcard can appear on different levels.
For illustration, let us discuss the difference between a
Collection<Pair<String,?>>
and a
Collection<? extends Pair<String,?>>
. For sake
of simplicity, let us assume
Pair
is a
final
class.
The type Collection<Pair<String,?>> is a concrete instantiation of the generic Collection interface. It is a heterogenous collection of pairs of different types. It can contain elements of type Pair<String,Long> , Pair<String,Date> , Pair<String,Object> , Pair<String,String> , and so on and so forth. In other words, Collection<Pair<String,?>> contains a mix of pairs of different types of the form Pair<String,?> . The type Collection<? extends Pair<String,?>> is a wildcard parameterized type; it does NOT stand for a concrete parameterized type. It stands for a representative from the family of collections that are instantiations of the Collection interface, where the type argument is of the form Pair<String,?> . Compatible instantiations are Collection<Pair<String,Long>> , Collection<Pair<String,String>> , Collection<Pair<String,Object>> , or Collection<Pair<String,?>> . In other words, we do not know which instantiation of Collection it stands for. As a rule of thumb, you have to read multi-level wildcards top-down. If the top-level type argument is a concrete type then the instantiation is a concrete type, probably a mixed bag of something, if the wildcard appears further down on a lower level. In this sense, a Collection<Pair<String,?>> is a collection of pairs of a certain form, that has lots of concrete subtypes. It's similar to a Collection<Object> , which is a collection of a concrete type that has lots of subtypes and is a mixed bag of something that is a subtype of Object .
If the top-level type argument is a wildcard, then the type is not concrete.
It is a placeholder for a representative from a family of types. In this
sense, a
Collection<? extends Pair<String,?>>
is a placeholder
for a collection instantiated for a particular unknown pair type of a certain
form. It's similar to a
Collection<?>
, which is a placeholder
for a specific instantiation of the
Collection
interface, but
it is not a concrete type.
Here is an example that illustrates the difference between Collection<Pair<String,?>> and Collection<? extends Pair<String,?>> . Example: Collection< Pair<String,Long> > c1 = new ArrayList<Pair<String,Long>>();Of course, we can assign a Collection<Pair<String,Long>> to a Collection<Pair<String,Long>> . There is nothing surprising here. But we can not assign a Collection<Pair<String,Long>> to a Collection<Pair<String,?>> . The parameterized type Collection<Pair<String,Long>> is a homogenous collection of pairs of a String and a Long ; the parameterized type Collection<Pair<String,?>> is a heterogenous collection of pairs of a String and something of unknown type. The heterogenous Collection<Pair<String,?>> could for instance contain a Pair<String,Date> and that clearly does not belong into a Collection<Pair<String,Long>> . For this reason the assignment is not permitted.
But then, we can assign a
Collection<Pair<String,Long>>
to a
Collection<? extends Pair<String,?>>
, because the type
Pair<String,Long>
belongs
to the family of types denoted by the wildcard
? extends Pair<String,?>
.
This is because the type family denoted by the wildcard
? extends Pair<String,?>
comprises all subtypes of
Pair<String,?>
. Since we assumed
that
Pair
is a
final
type, this type family includes
all instantiations of the generic type
Pair
where the first type
argument is
String
and second type argument is an arbitrary type
or wildcard. The type family includes members such as
Pair<String,Long>
,
Pair<String,Object>
,
Pair<String,?
extends Number>
, and
Pair<String,?>
itself.
If we give up the simplification that Pair is a final class, then we must also consider subtypes of Pair . Collection<Pair<String,?>> is then a heterogenous collection of pairs of different types of the form Pair<String,?> , or subtypes thereof . It can contain elements of type Pair<String,Long> , Pair<String,Date> , but also elements of type SubTypeOfPair<String,Date> , SubTypeOfPair<String,Object> , and so on and so forth. Collection<? extends Pair<String,?>> stands for a representative from the family of collections that are instantiations of the Collection interface, where the type argument is of the form Pair<String,?> , or subtypes thereof . Compatible parameterized types are Collection<Pair<String,Long>> , Collection<Pair<String,Object>> , but also Collection<SubTypeOfPair<String,Object>> , or Collection<SubTypeOfPair<String,?>> . Here is an example that illustrates the difference between the concrete parameterized type Collection<Pair<String,?>> and the wildcard parameterized type Collection<? extends Pair<String,?>> . Example: Collection< SubTypeOfPair<String,Long> > c1 = new ArrayList<SubTypeOfPair<String,Long>>();In this case, we can not assign a Collection<SubTypeOfPair<String,Long>> to a Collection<Pair<String,Long>> , because these two instantiations of the generic type Collection are unrelated and incompatible types. The Collection<SubTypeOfPair<String,Long>> contains SubTypeOfPair<String,Long> objects, whereas the Collection<Pair<String,Long>> contains a mix of objects of types that are subtypes of type Pair<String,Long> . This includes, but is not limited to objects of type SubTypeOfPair<String,Long> . For this reason a Collection<SubTypeOfPair<String,Long>> cannot be assigned to a Collection<Pair<String,Long>> . Also, we can not assign a Collection<SubTypeOfPair<String,Long>> to a Collection<Pair<String,?>> because the parameterized type Collection<SubTypeOfPair<String,Long>> is a homogenous collection of objects of type SubTypeOfPair<String,Long> , whereas the parameterized type Collection<Pair<String,?>> is a heterogenous collection. The heterogenous Collection<Pair<String,?>> could for instance contain a Pair<String,Date> and that clearly does not belong in a Collection<SubTypeOfPair<String,Long>> . The assignment of a Collection<SubTypeOfPair<String,Long>> to a Collection<? extends Pair<String,?>> is fine because the type SubTypeOfPair<String,Long> belongs to the family of types denoted by the wildcard ? extends Pair<String,?> . This is because the type family denoted by the wildcard ? extends Pair<String,?> comprises all subtypes of Pair<String,?> . Since we no longer assumed that Pair is a final type, this type family includes all instantiations of the generic type Pair and any of its subtypes where the first type argument is String and second type argument is an arbitrary type or wildcard. The type family includes members such as Pair<String,Long> , Pair<String,Object> , Pair<String,? extends Number> , and Pair<String,?> itself, but also SubTypeOfPair<String,Long> , SubTypeOfPair<String,Object> , SubTypeOfPair<String,? extends Number> , and SubTypeOfPair<String,?> . |
|
| LINK TO THIS | TypeArguments.FAQ104 |
| REFERENCES |
What
is the difference between a Collection<?> and a Collection<Object>?
Which super-subset relationships exist among wildcards? What is the difference between a Collection<Pair<String,Object>>, a Collection<Pair<String,?>> and a Collection<? extends Pair<String,?>>? |
| No, each occurrence can stand for a different type. | |
|
If the same wildcard appears repeatedly in a type argument
section each occurrence of the wildcard refers to a potentially different
type. It is similar to wildcards in a regular expression: in "s??"
the wildcard need not stand for the same character. "see", but also
"sea" or "sew" or "saw" would be matching expressions. Each question mark
stands for a potentially different character. The same holds for wildcards
in Java generics.
Example (using the same wildcard repeatedly): Pair< ? , ? > couple = new Pair< String , String >("Orpheus","Eurydike");In the example above, the wildcard " ? " can stand for the same type, such as String , but it need not do so. Each wildcard can stand for a different type, such as String and Date for instance. Conversely, different wildcards need not stand for different types. If the type families denoted by the two different wildcards overlap, then the two different wildcards can stand for the same concrete type. Example (using different wildcards): Pair< ? extends Appendable , ? extends CharSequence > textPlusSuffixIn the examples above, the different wildcards " ? extends Appendable " and " ? extends CharSequence " can stand for different types, such as StringBuilder and String , but they can equally well stand for the same type, such as StringBulder , provided the bounds permit it. Below are a couple of examples where the same wildcard appears repeatedly and where the compiler rightly issues an error message. In the first example the wildcard appears twice in an parameterized type, namely in Pair<?,?> . Example #1 (demonstrating the incompatibility of one wildcard to another): class Pair<S,T> {The fields of the Pair<?,?> may be of different types. For instance, when the flip method is invoked with an argument of type Pair<String,Date> , then first would be of type String , while second is of type Date , and the fields cannot be assigned to each other. Even if the flip method is invoked with an argument of type Pair<String,String> , i.e. both wildcards stand for the same type, namely String , the compiler does not know this inside the implementation of the flip method. For this reason the compiler issues an error message in the implementation of the flip method when the two fields of unknown - and potentially different types - are assigned to each other. In the second example the wildcard appears in an two instantiations of the same generic type, namely in Collection<?> . Example #2 (demonstrating the incompatibility of one wildcard to another): class Utilities {The two collections contain elements of two potentially different unknown types. The compiler complains when elements from one collection are passed to the other collection, because the types of the elements might be incompatible. In the third example the wildcard appears in an two instantiations of two different generic type, namely in Collection<? extends CharSequence> and Class<? extends CharSequence> . Example #3 (demonstrating the incompatibility of one wildcard to another): class Utilities {The newInstance method of class Class<? extends CharSequence> creates an object of an unknown subtype of CharSequence , while the collection Collection<? extends CharSequence> holds elements of a potentially different subtype of CharSequence . The compiler complains when the newly created object is passed to the collection, because the collection might hold objects of an incompatible type. |
|
| LINK TO THIS | TypeArguments.FAQ105 |
| REFERENCES |
What
is a wildcard instantiation?
How can I make sure that the same wildcard stand for the same type? What is a wildcard bound? What is an unbounded wildcard? What is a bounded wildcard? Which super-subset relationships exist among wildcards? |
| A reference type that is used to further describe the family of types denoted by a wildcard. | |
|
A wildcard can be unbounded, in which case it is denoted
as "
?
". The unbounded wildcard stands for the family of
all
types.
Alternatively a wildcard can have a bound. There are two types of bounds: upper and lower bounds. The syntax for a bounded wildcard is either " ? extends SuperType " (wildcard with upper bound) or " ? super SubType " (wildcard with lower bound). The terms "upper" and "lower" stem from the way, in which inheritance relationships between types are denoted in modeling languages such as UML for instance. The bound shrinks the family of types that the wildcard stands for. For instance, the wildcard " ? extends Number " stands for the family of subtypes of Number ; type Number itself is included in the family. The wildcard " ? super Long " stands for the family of supertypes of Long ; type Long itself is included. Note, a wildcard can have only one bound. In can neither have both an upper and a lower bound nor several upper or lower bounds. Constructs such as " ? super Long extends Number " or " ? extends Comparable<String> & Cloneable " are illegal. |
|
| LINK TO THIS | TypeArguments.FAQ201 |
| REFERENCES |
What
is a wildcard?
Which types are permitted as wildcard bounds? What is the difference between a wildcard bound and a type parameter bound? |
| All references types including parameterized types, but no primitive types. | |
|
All reference types can be used as a wildcard bound.
This includes classes, interfaces, enum types, nested and inner types,
and array types. Only primitive types cannot be used as wildcard
bound.
Example (of wildcard bounds): List<? extends int > l0; // errorThe example only shows the various reference types as upper bound of a wildcard, but these type are permitted as lower bound as well. We can see that primitive types such as int are not permitted as wildcard bound. Class types, such as String , and interface types, such as Runnable , are permitted as wildcard bound. Enum types, such as TimeUnit (see java.util.concurrent.TimeUnit ) are also permitted as wildcard bound. Note, that even types that do not have subtypes, such as final classes and enum types, can be used as upper bound. The resulting family of types has exactly one member then. For instance, " ? extends String " stands for the type family consisting of the type String alone. Following the same line of logic, the wildcard " ? super Object " is permitted, too, although class Object does not have a supertype. The resulting type family consists of type Object alone. Raw types are permitted as wildcard bound; Comparable is an example. Thread.State is an example of a nested type; Thread.State is an enum type nested into the Thread class. Non-static inner types are also permitted. An array type, such as int[] and Object[] , is permitted as wildcard bound. Wildcards with an array type as a bound denote the family of all sub- or supertypes of the wildcard type. For instance, " ? extends Object[] " is the family of all array types whose component type is a reference type. int[] does not belong to that family, but Integer[] does. Similarly, " ? super Number[] " is the family of all supertypes of the array type, such as Object[] , but also Object , Cloneable and Serializable .
Parameterized types are permitted as wildcard bound, including concrete
parameterized types such as
Callable<String>
, bounded
wildcard parameterized types such as
Comparable<? super Long>
and
Class<?
extends Number>
, and unbounded wildcard parameterized types such as
Map.Entry<?,?>
.
Even the primordial supertype of all enum types, namely class
Enum
,
can be used as wildcard bound.
|
|
| LINK TO THIS | TypeArguments.FAQ202 |
| REFERENCES |
What
is a wildcard?
What is a wildcard bound? |
|
A wildcard can have only one bound, while
a type parameter can have several bounds.
A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter. |
|||||||||||
|
Wildcard bounds and type parameter bounds are often confused,
because they are both called bounds and have in part similar syntax.
Example (of type parameter bound and wildcard bound): class Box< T extends Appendable & Flushable > {The code sample above shows a type parameter T with two bounds, namely Appendable and Flushable , and a wildcard with an upper bound T . The type parameter bounds give access to their non-static methods. For instance, in the example above, the bound Flushable makes is possible that the flush method can be invoked on variables of type T . In other words, the compiler would accept an expression such as theObject.flush(). The wildcard bound describes the family of types that the wildcard stands for. In the example, the wildcard " ? extends T " denotes the family of all subtypes of T . It is used in the argument type of a constructor and permits that box objects of a box type from the family Box<? extends T> can be supplied as constructor arguments. It allows that a Box<Writer> can be constructed from a Box<PrintWriter> , for instance.
The syntax is similar and yet different:
A wildcard can have only one bound, either a lower or an upper bound. A list of wildcard bounds is not permitted. A type parameter, in constrast, can have several bounds, but there is no such thing as a lower bound for a type parameter. |
|||||||||||
| LINK TO THIS | TypeArguments.FAQ203 | ||||||||||
| REFERENCES |
What
is a wildcard?
What is a wildcard bound? What is a type parameter? What is a type parameter bound? Why is there no lower bound for type parameters? |
||||||||||