Java.Core.WildcartReadWriteLimitations

This is one of the most confusing (but important) parts of generics and wildcards in Java. Let me explain this step by step — and once you understand the logic, it will make perfect sense. 🔥


🧩 The Core Problem: Type Safety

When you have an unbounded wildcard, like this:

List<?> list = new ArrayList<String>();

The wildcard ? means:

“This list can hold elements of some type, but I don’t know which type exactly.”

🚨 Why Adding Elements is Dangerous

Since the compiler doesn’t know what type exactly ? stands for, it cannot guarantee type safety if you try to add something.

For example:

List<?> list = new ArrayList<String>();  // Currently holds Strings

list.add("hello");  // Compile error: incompatible types
list.add(42);       // Compile error: incompatible types

🧰 What type is ? really?

  • It could be a List<String>.
  • It could be a List<Integer>.
  • It could be a List<User>.

Since the compiler doesn’t know, it must block all “add” operations to prevent potential type mismatches.


💥 Example of the Danger (if adding was allowed)

Imagine this:





List<?> list = new ArrayList<String>();

list.add(42);  // What if this was allowed?
String str = (String) list.get(0);  // BOOM - ClassCastException!

The compiler has no way to check what type ? is, so it cannot allow adding any object — the only safe value to add is null (since null is type-compatible with everything).


✅ What is Allowed

OperationAllowed?Reason
list.add(...)Unsafe — compiler doesn’t know the type.
list.add(null)null fits any type.
list.get(...)Safe — result is Object (superclass of all types).
list.size()No type involved here.

🔑 Summary Rule

You cannot add elements to a List<?> because the type is unknown.

You can read elements (as Object), since every type extends Object.


⚙️ Mnemonic

✅ Safe for reading (because all types are Object)

❌ Unsafe for writing (except null, which is type-neutral)


📦 Example for Clarity

public static void processList(List<?> list) {
    // list.add("hello");  // ❌ Doesn't compile
    // list.add(new Object());  // ❌ Doesn't compile

    list.add(null);  // ✅ This is allowed

    Object item = list.get(0);  // ✅ Safe, we know it's at least an Object
    System.out.println(item);
}

📣 Important: This applies only to ? wildcards — if the type is known (like List<String>), adding is perfectly fine.

✅ 1. ? extends T — Upper Bounded Wildcard

List<? extends Number> list = new ArrayList<Integer>();  // Integer extends Number

🔗 What does ? extends Number mean?

This list could be a List<Number>, List<Integer>, List<Double>, etc.
The exact type is unknown to the compiler — it only knows it’s some subtype of Number.


🚨 Can You Add Elements?

NO, you cannot add anything (except null).

list.add(42);        // Compile error
list.add(3.14);      // Compile error
list.add(new Number());  // Compile error
list.add(null);      // ✅ This is allowed (null fits all types)

💣 Why Adding is Blocked?

The compiler doesn’t know the exact type of the list. It only knows it’s some subclass of Number, but which one? Could be:

  • List<Integer>
  • List<Double>
  • List<Float>

If you try to add an Integer, it might actually be a List<Double>, which would break type safety.


✅ Can You Read Elements?

YES, you can safely read — but as Number, the upper bound.

Number n = list.get(0);  // Safe

🔥 Summary for ? extends T

OperationAllowed?Why?
Add elementsUnsafe, could break type safety.
Add nullAlways safe.
Read elementsSafe as Number (the upper bound).

✅ 2. ? super T — Lower Bounded Wildcard

Example:

List<? super Integer> list = new ArrayList<Number>();  // Number is a supertype of Integer

🔗 What does ? super Integer mean?

This list could be a List<Integer>, List<Number>, or even a List<Object>.
The compiler only knows the lower bound — the list can hold at least Integer or anything above it in the type hierarchy.


✅ Can You Add Elements?

YES, you can add Integer and its subtypes (if any).

list.add(42);        // ✅ Integer fits
list.add(null);      // ✅ null fits all
// list.add(new Object());  // ❌ Doesn't work

🚨 Can You Read Elements?

NO (or very limited) — You can only read them as Object.





Object obj = list.get(0);  // Only safe option
// Integer i = list.get(0);  // Compile error

Why? Because the actual list could be List<Object> — so the compiler only guarantees that the items are at least Object, not necessarily Integer.


🔥 Summary for ? super T

OperationAllowed?Why?
Add T or subtypeAlways safe.
Add nullAlways safe.
Read elements✅ But only as ObjectActual type might be a supertype (like Object).

🚀 Final Recap Table

WildcardAdd?Read?
? (unbounded)❌ (except null)✅ as Object
? extends T❌ (except null)✅ as T (upper bound)
? super T✅ (T and subtypes)✅ as Object

💡 Mnemonic

WildcardMeaningRule
? extends TProducerYou can read safely (it produces), but can’t add.
? super TConsumerYou can add safely (it consumes), but reading is limited.

🔗 Quick Analogy

Think of it like a vending machine vs. a donation box:

WildcardAnalogy
? extends TVending machine — you can take out items, but you can’t put your own inside because you don’t know exactly what the machine accepts.
? super TDonation box — you can put items inside (it will accept anything “compatible”), but when you take something out, you might not know exactly what you get (so you handle it as Object).
This entry was posted in Без рубрики. Bookmark the permalink.