A class or interface whose declaration has one or more type parameters is a generic class or interface [JLS, 8.1.2, 9.1.2]. For example, the
// Raw collection type - don't do this!
// My stamp collection. Contains only Stamp instances.
private final Collection stamps = ... ;
// Erroneous insertion of coin into stamp collection
stamps.add(new Coin( ... )); // Emits "unchecked call" warning
// Raw iterator type - don't do this!
for (Iterator i = stamps.iterator(); i.hasNext(); )
Stamp stamp = (Stamp) i.next(); // Throws ClassCastException
stamp.cancel();
// Parameterized collection type - typesafe
private final Collection<Stamp> stamps = ...
Test.java:9: error: incompatible types: Coin cannot be converted
to Stamp
c.add(new Coin());
It was deemed critical that all of this code remain legal and interoperate with newer code that does use generics. It had to be legal to pass instances of parameterized types to methods that were designed for use with raw types, and vice versa. This requirement, known as migration compatibility, drove the decisions to support raw types and to implement generics using erasure(Item 28).
As a consequence, you lose type safety if you use a raw type such as
// Fails at runtime - unsafeAdd method uses a raw type (List)!
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
String s = strings.get(0); // Has compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
Test.java:10: warning: [unchecked] unchecked call to add(E) as a
member of the raw type List
list.add(o);
Test.java:5: error: incompatible types: List<String> cannot be
converted to List<Object>
unsafeAdd(strings, Integer.valueOf(42));
// Use of raw type for unknown element type - don't do this!
static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
What is the difference between the unbounded wildcard type
WildCard.java:13: error: incompatible types: String cannot be
converted to CAP#1
c.add("verboten");
^
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?. You must use raw types in class literals. The specification does not permit the use of parameterized types (though it does permit array types and primitive types) [JLS, 15.8.2]. In other words,
This is the preferred way to use the
// Legitimate use of raw type - instanceof operator
if (o instanceof Set) { // Raw type
Set<?> s = (Set<?>) o; // Wildcard type
...
}
List
interface has a single type parameter, E
, representing its element type. The full name of the interface is List<E>
(read “list of E
”), but people often call it List
for short. Generic classes and interfaces are collectively known as generic types.// Raw collection type - don't do this!
// My stamp collection. Contains only Stamp instances.
private final Collection stamps = ... ;
// Erroneous insertion of coin into stamp collection
stamps.add(new Coin( ... )); // Emits "unchecked call" warning
// Raw iterator type - don't do this!
for (Iterator i = stamps.iterator(); i.hasNext(); )
Stamp stamp = (Stamp) i.next(); // Throws ClassCastException
stamp.cancel();
// Parameterized collection type - typesafe
private final Collection<Stamp> stamps = ...
Test.java:9: error: incompatible types: Coin cannot be converted
to Stamp
c.add(new Coin());
It was deemed critical that all of this code remain legal and interoperate with newer code that does use generics. It had to be legal to pass instances of parameterized types to methods that were designed for use with raw types, and vice versa. This requirement, known as migration compatibility, drove the decisions to support raw types and to implement generics using erasure(Item 28).
As a consequence, you lose type safety if you use a raw type such as
List
, but not if you use a parameterized type such asList<Object>
.// Fails at runtime - unsafeAdd method uses a raw type (List)!
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
String s = strings.get(0); // Has compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
Test.java:10: warning: [unchecked] unchecked call to add(E) as a
member of the raw type List
list.add(o);
Test.java:5: error: incompatible types: List<String> cannot be
converted to List<Object>
unsafeAdd(strings, Integer.valueOf(42));
// Use of raw type for unknown element type - don't do this!
static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
What is the difference between the unbounded wildcard type
Set<?>
and the raw type Set
? Does the question mark really buy you anything? Not to belabor the point, but the wildcard type is safe and the raw type isn’t. You can put any element into a collection with a raw type, easily corrupting the collection’s type invariant (as demonstrated by the unsafeAdd
method on page 119); you can’t put any element (other than null
) into a Collection<?>
. Attempting to do so will generate a compile-time error message like this:WildCard.java:13: error: incompatible types: String cannot be
converted to CAP#1
c.add("verboten");
^
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?. You must use raw types in class literals. The specification does not permit the use of parameterized types (though it does permit array types and primitive types) [JLS, 15.8.2]. In other words,
List.class
, String[].class
, and int.class
are all legal, but List<String>.class
and List<?>.class
are not.This is the preferred way to use the
instanceof
operator with generic types:// Legitimate use of raw type - instanceof operator
if (o instanceof Set) { // Raw type
Set<?> s = (Set<?>) o; // Wildcard type
...
}
Term
|
Example
|
Item
|
Parameterized type
| List<String> |
Item 26
|
Actual type parameter
| String |
Item 26
|
Generic type
| List<E> |
Items 26, 29
|
Formal type parameter
| E |
Item 26
|
Unbounded wildcard type
| List<?> |
Item 26
|
Raw type
| List |
Item 26
|
Bounded type parameter
| <E extends Number> |
Item 29
|
Recursive type bound
| <T extends Comparable<T>> |
Item 30
|
Bounded wildcard type
| List<? extends Number> |
Item 31
|
Generic method
| static <E> List<E> asList(E[] a) |
Item 30
|
Type token
| String.class |
Item 33
|
No comments:
Post a Comment