Java Generics Wildcards – Complete Guide with Examples


Learn how to use wildcards in Java Generics for flexible method parameters, including unbounded, upper-bounded, and lower-bounded wildcards with practical examples.

Wildcards in Java Generics – Complete Detailed Tutorial

Wildcards in Java Generics allow flexibility in specifying generic types, especially for method arguments, without losing type safety.

1. What are Wildcards?

  1. Represent an unknown type in generics
  2. Syntax: <?>
  3. Useful in methods and collections where type can vary
  4. Helps avoid code duplication

2. Types of Wildcards

2.1 Unbounded Wildcard <?>

  1. Represents any type
  2. Useful when you don’t care about the exact type

Example – Unbounded Wildcard


import java.util.Arrays;
import java.util.List;

public class Main {
public static void printList(List<?> list) {
for(Object obj : list) {
System.out.print(obj + " ");
}
System.out.println();
}

public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<String> strings = Arrays.asList("A", "B", "C");

printList(numbers);
printList(strings);
}
}

Output:


1 2 3
A B C

Key Points:

  1. Can read elements as Object
  2. Cannot add elements (except null)

2.2 Upper-Bounded Wildcard <? extends Class>

  1. Represents subclasses of a specified class
  2. Allows reading elements safely
  3. Cannot add elements except null

Example – Upper-Bounded Wildcard


import java.util.Arrays;
import java.util.List;

class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }

public class Main {
public static void printAnimals(List<? extends Animal> animals) {
for(Animal a : animals) {
System.out.println(a.getClass().getSimpleName());
}
}

public static void main(String[] args) {
List<Dog> dogs = Arrays.asList(new Dog(), new Dog());
List<Cat> cats = Arrays.asList(new Cat(), new Cat());

printAnimals(dogs);
printAnimals(cats);
}
}

Output:


Dog
Dog
Cat
Cat

Key Points:

  1. Read-only for method
  2. Ensures type safety for subclasses

2.3 Lower-Bounded Wildcard <? super Class>

  1. Represents superclasses of a specified class
  2. Useful when writing elements to a collection
  3. Cannot read elements as the specific type (can read as Object)

Example – Lower-Bounded Wildcard


import java.util.ArrayList;
import java.util.List;

class Animal { }
class Dog extends Animal { }

public class Main {
public static void addDogs(List<? super Dog> list) {
list.add(new Dog());
}

public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
addDogs(animals);
System.out.println("List size: " + animals.size());
}
}

Output:


List size: 1

Key Points:

  1. Write-only for method
  2. Ensures type safety when adding subclasses

3. Summary Table of Wildcards

WildcardMeaningCan ReadCan Write
<?>Any typeYes (as Object)No
<? extends T>T or subclassYesNo (except null)
<? super T>T or superclassLimited (as Object)Yes

4. Key Points

  1. Wildcards increase flexibility of generics
  2. Upper-bound → use when reading
  3. Lower-bound → use when writing
  4. Unbounded → use when type doesn’t matter
  5. Avoid casting and duplication in generic methods