Java.Core.GenericWildcard

🏆 What Are Wildcards (?) in Java?

Wildcards allow you to use unknown types in generics. They are useful when working with collections of different but related types.

Types of Wildcards in Java

WildcardMeaningExample
? (Unbounded)Accepts any typeList<?> list = new ArrayList<String>();
? extends T (Upper Bounded)Accepts T or any subclass of TList<? extends Number> list = new ArrayList<Integer>();
? super T (Lower Bounded)Accepts T or any superclass of TList<? super Integer> list = new ArrayList<Number>();

1. Unbounded Wildcard (?)

  • Use Case: When the type doesn’t matter (read-only operations).
  • Example:
public static void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

List<String> names = List.of("Alice", "Bob");
List<Integer> numbers = List.of(1, 2, 3);

printList(names);   // Works
printList(numbers); // Works

Rules:

  • You can’t add elements to a List<?> (except null) because the type is unknown.
  • Only reading is allowed.

2. Upper Bounded Wildcard (? extends T)

  • Use Case: When you want to accept T or any of its subclasses but ensure safe reading.
  • Example:
public static double sumList(List<? extends Number> list) {
    double sum = 0;
    for (Number num : list) {
        sum += num.doubleValue();  // Safe: We know it’s at least a Number
    }
    return sum;
}

List<Integer> intList = List.of(1, 2, 3);
List<Double> doubleList = List.of(1.5, 2.5, 3.5);

System.out.println(sumList(intList));   // Works
System.out.println(sumList(doubleList)); // Works

Rules:

  • Reading is allowed (Number num = list.get(i);)
  • Writing is NOT allowed (list.add(10); won’t compile!)

3. Lower Bounded Wildcard (? super T)

  • Use Case: When you want to accept T or any of its superclasses, ensuring safe writing.
  • Example:
public static void addNumbers(List<? super Integer> list) {
    list.add(10); // Allowed
    list.add(20); // Allowed
    // list.add(3.14); // ERROR: Only Integers or their subclasses allowed
}

List<Integer> intList = new ArrayList<>();
List<Number> numList = new ArrayList<>();

addNumbers(intList); // Works
addNumbers(numList); // Works

Rules:

  • Writing is allowed (list.add(new Integer(10));)
  • Reading is limited (Object obj = list.get(i); but NOT Integer num = list.get(i);)

🤔 When to Use Which Wildcard?

Use CaseWildcard to Use
Read-only access to unknown type? (Unbounded)
Reading from a list of unknown subtypes? extends T (Upper Bounded)
Writing to a list of unknown supertypes? super T (Lower Bounded)

🔥 Quick Mnemonic:

  1. Producer (extends) — Use ? extends T for reading.
    • “If it produces, it extends.”
    • Example: List<? extends Number> list → You can read Numbers, but not add anything.
  2. Consumer (super) — Use ? super T for writing.
    • “If it consumes, it super.”
    • Example: List<? super Integer> list → You can add Integers, but only read Objects.

🏁 Final Thoughts

Wildcards make Java generics more flexible while keeping type safety. They help when working with collections of different but related types and let you enforce safe read/write access.

Would you like to see more real-world examples or need further clarifications? 😊

This entry was posted in Без рубрики. Bookmark the permalink.