Multiple Bounds
A type variable with multiple bounds is a subtype of all the types listed in the bound. If one of the bounds is a class, it must be specified first.
Upper Bounded Wildcards List<? extends Foo> list
The term List<Number> is more restrictive than List<? extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses.
Unbounded Wildcards printList(List<?> list)
It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into aList<?>.
a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.
To write the method that works on lists of Integer and the supertypes of Integer, such as Integer, Number, and Object, you would specify List<? super Integer>. The termList<Integer> is more restrictive than List<? super Integer> because the former matches a list of type Integer only, whereas the latter matches a list of any type that is a supertype of Integer.
Since we don't know what the element type of
Since we don't know what the element type of
On the other hand, given a
You should be able to figure out why the code above is disallowed. The type of the second parameter to
Wildcard Guidelines:
A list defined by List<? extends ...> can be informally thought of as read-only, but that is not a strict guarantee.
Because List<EvenNumber> is a subtype of List<? extends NaturalNumber>, you can assign le to ln. But you cannot use ln to add a natural number to a list of even numbers. The following operations on the list are possible:
A type variable with multiple bounds is a subtype of all the types listed in the bound. If one of the bounds is a class, it must be specified first.
Upper Bounded Wildcards List<? extends Foo> list
The term List<Number> is more restrictive than List<? extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses.
Unbounded Wildcards printList(List<?> list)
The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach:
Because for any concrete type A, List<A> is a subtype of List<?>, you can use printList to print a list of any type:- If you are writing a method that can be implemented using functionality provided in the Object class.
- When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> do not depend on T.
Lower Bounded Wildcards List<? super Integer> list
To write the method that works on lists of Integer and the supertypes of Integer, such as Integer, Number, and Object, you would specify List<? super Integer>. The termList<Integer> is more restrictive than List<? super Integer> because the former matches a list of type Integer only, whereas the latter matches a list of any type that is a supertype of Integer.
Although Integer is a subtype of Number, List<Integer> is not a subtype of List<Number> and, in fact, these two types are not related. The common parent of List<Number> andList<Integer> is List<?>.
List<? extends Integer> intList = new ArrayList<>(); List<? extends Number> numList = intList; // OK. List<? extends Integer> is a subtype of List<? extends Number>
Wildcards
It isn't safe to add arbitrary objects to it however:Collection<?> c = new ArrayList<String>(); c.add(new Object()); // Compile time error
c
stands for, we cannot add objects to it.Since we don't know what the element type of
c
stands for, we cannot add objects to it. The add()
method takes arguments of type E
, the element type of the collection. When the actual type parameter is ?
, it stands for some unknown type. Any parameter we pass to add
would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null
, which is a member of every type.On the other hand, given a
List<?>
, we can call get()
and make use of the result. The result type is an unknown type, but we always knBounded Wildcards
public void addRectangle(List<? extends Shape> shapes) { // Compile-time error! shapes.add(0, new Rectangle()); }
shapes.add()
is ? extends Shape
-- an unknown subtype of Shape
. Since we don't know what type it is, we don't know if it is a supertype of Rectangle
;Wildcard Capture and Helper Methods
You can fix it by writing a private helper method which captures the wildcard.
void foo(List<?> i) { fooHelper(i); } // Helper method created so that the wildcard can be captured // through type inference. private <T> void fooHelper(List<T> l) { l.set(0, l.get(0)); }
Effects of Type Erasure and Bridge Methods
To implement generics, the Java compiler applies type erasure to:
- Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
- Insert type casts if necessary to preserve type safety.
- Generate bridge methods to preserve polymorphism in extended generic types.
Bridge Methods
After type erasure, the method signatures do not not match. The Node method becomes setData(Object) and the MyNode method becomes setData(Integer). Therefore, the MyNodesetData method does not override the Node setData method.To solve this problem and preserve the polymorphism of generic types after type erasure, a Java compiler generates a bridge method to ensure that subtyping works as expected.
public void setData(Integer data) { System.out.println("MyNode.setData"); super.setData(data);
}
Guidelines for Wildcard Use
- An "in" variable is defined with an upper bounded wildcard, using the extends keyword.
- An "out" variable is defined with a lower bounded wildcard, using the super keyword.
- In the case where the "in" variable can be accessed using methods defined in the Object class, use an unbounded wildcard.
- In the case where the code needs to access the variable as both an "in" and an "out" variable, do not use a wildcard.
A list defined by List<? extends ...> can be informally thought of as read-only, but that is not a strict guarantee.
Because List<EvenNumber> is a subtype of List<? extends NaturalNumber>, you can assign le to ln. But you cannot use ln to add a natural number to a list of even numbers. The following operations on the list are possible:
- You can add null.
- You can invoke clear.
- You can get the iterator and invoke remove.
- You can capture the wildcard and write elements that you've read from the list.