static
/ ... /
}
you cannot pass a reference of type List<?> because the inferred type of T will be "captureof?" and
there is no type compatible with "captureof?" that you could possibly pass for the parameter t. Or
looking at it the other way, T will be determined by whatever you pass for t, and whatever it is, it cannot be
"captureof?", so the type of T would not be uniquely determined.
11.5. Under the Hood: Erasure and Raw Types
As we have stated a number of times, for each generic type there is only one class, no matter how many
different parameterized types are formed from it. This raises the question: What exactly is that type? Given a
class like Cell
To determine the answer the compiler uses a process called erasure (because the compiler essentially erases
all generic type information from the compiled class). The erasure of a generic or parameterized type is
simply the unadorned type name. This is also known as the raw type (see "Raw Types, "Unchecked"
Warnings, and Bridge Methods" on page 745). For example, the erasure of Cell
erasure of a type variable is the erasure of its first bound. For example, the erasure of E in
implicit upper bound. The erasure of E in
it is in <EextendsNumber&Cloneable>, because Number is the first bound. The compiler generates a
class definition for the erasure of a generic type by effectively replacing each type variable with its erasure.
When a parameterized type is used and the type information from the erasure of the generic type doesn't
match what is expected, the compiler inserts a cast. For example, if you invoke remove on an object created
as a SingleLinkQueue
String because the erasure of the type variable in SingleLinkQueue
You need to understand the erasure process because it impacts your programs in two key areas:
- The runtime actions that can involve generic types
- Method overloading and overriding
We start with the runtime issues.
11.5.1. Erasure at Runtime
The runtime impact of erasure is simple to state: Nothing that needs to know the value of a type argument at
runtime is allowed. This has the following consequences, some of which we have already discussed:
You cannot instantiate a type represented only as a type parameter, nor can you create an array of
such a type. So for a type variable T you can't do newT() or newT[n].
•
You cannot create an array whose element type is a parameterized type, with the exception of a
parameterized type for which all the type arguments are unbounded wildcards. For example,
"newList<String>[1] " is invalid, whereas "newList<?>[1] " is okay.
•
You cannot use instanceof to see if an object is an instance of a parameterized type, again with
the exception of a parameterized type whose type arguments are all unbounded wildcards. The
instanceof test is a runtime test, and at runtime the parameterized type has been replaced by its
erasure. Since this is unlikely to perform the test you expected, the compiler rejects it. You can
replace the parameterized type by its erasure if that is what you really wanted to test.