Introduction
The wildcard mark (?
) can help us write a program in a more explicit way.
It's used to represent an unknown type and is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.
Example
Let's assume we have an object hierarchy:
- The
Animal
class inherits fromObject
trivially - The
Dog
andCat
classes both inherit fromAnimal
- The
GoldenRetriever
class inherits fromDog
In general, there're 3 ways to use a wildcard:
Upper bound:
void fun(List<? extends Animal> list)
This input list is parameterized over at most typeAnimal
(can be any subtype ofAnimal
)
Lower bound:
void fun(List<? super Animal> list)
This input list is parameterized over at least typeAnimal
(can be any supertype ofAnimal
)
-
Unbounded:
void fun(List<?> list) { list.clear(); }
- Here we don't care what the type of the list is since
clear()
isn't type dependent. - If we were supposed to use only methods defined in
Object
, then unbounded wildcard works fine.
- Here we don't care what the type of the list is since
Java Demo Code
See the following code,
WildcardDemo.java
, for better understanding.
First, try to compile it with javac WildcardDemo.java
and see the error console :)
Second, to successfully compile the code, note that there're 2 lines marked as // X (can't compiled)
, you should comment them in order to compile the code.
The code is fully commented. Feel free to leave any comment if you're not understanding.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Our Object Hierarchy:
*
* Object
* |
* Animal
* / \
* Dog Cat
* |
* GoldenRetriever
*/
public class WildcardDemo {
private class Animal {}
private class Dog extends Animal {}
private class Cat extends Animal {}
private class GoldenRetriever extends Dog {}
// `animals` is parameterized over "at most" type `Animal`
private void funExtends(List<? extends Animal> animals) {
// Can't add a Dog (subtype) to the `animals` because it may
// contain something "lower than an Animal".
// For example, it might be `List<GoldenRetriever>` or `List<Cat>`
animals.add(new Dog()); // X (can't compiled)
// Can't put anything into a type declared with an extends
// wildcard except for the value `null`, which is a subtype
// of every reference type
animals.add(null);
// Can retrieve an `Animal`, because any subtype of `Animal`
// must be an `Animal`
Animal animal = animals.get(0);
System.out.println(animal.getClass().toString());
}
// `animals` is parameterized over "at least" type `Animal`
private void funSuper(List<? super Animal> animals) {
// Can add a `Dog` (subtype) to the `animals` because a `Dog`
// is guaranteed an `Animal` or any supertype of an `Animal`
animals.add(new Dog());
// Can't get anything out from a type declared with a super
// wildcard except for a value of type `Object`, which is a
// super type of every reference type
Animal animal = animals.get(0); // X (can't compiled)
Object object = animals.get(1);
System.out.println(object.getClass().toString());
}
private List<Animal> getAnimals() {
return new ArrayList<>(Arrays.asList(
new GoldenRetriever(),
new Cat()
)
);
}
public static void main(String[] args) {
WildcardDemo demo = new WildcardDemo();
List<Animal> animals = demo.getAnimals();
demo.funExtends(animals);
demo.funSuper(animals);
}
}
Top comments (0)