Skip to content

Commit 0d0b9ed

Browse files
authored
Update collections.md
1 parent 82c3c8b commit 0d0b9ed

1 file changed

Lines changed: 58 additions & 3 deletions

File tree

collections.md

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ layout: default
1010
**PECS Rule:** **P**roducer **E**xtends, **C**onsumer **S**uper
1111

1212
- `? extends T`: **READ-ONLY** - Can read items of type T or its subtypes. Cannot add anything (except `null`)
13-
- `? super T`: **WRITE-ONLY** - Can write T or its subtypes. Cannot safely read (except `Object`)
13+
- `? super T`: **WRITE-ONLY** - Can write T or its subtypes. Cannot safely read (except as `Object`)
1414

15+
### Basic PECS Example
1516
```java
1617
// Producer Extends - Reading from a collection
1718
List<? extends Number> numbers = List.of(1, 2.0, 3L);
@@ -26,7 +27,61 @@ values.add(42); // ✅ OK - can write Integer/subtypes
2627
Object obj = values.get(0); // ✅ OK - can read as Object
2728
```
2829

29-
**💡 Learning Tip:** Think of wildcards as "one-way streets" - extends for reading OUT, super for writing IN.
30+
### Family Hierarchy Example
31+
```java
32+
class Grandparent {
33+
}
34+
class Parent extends Grandparent {
35+
}
36+
class Child extends Parent {
37+
}
38+
39+
public class FamilyGenericTest {
40+
Grandparent grandparent = new Grandparent();
41+
Child child = new Child();
42+
43+
public void acceptOlderGenerations(List<? super Parent> familyList) {
44+
// Can ADD Parent and younger generations (Child)
45+
familyList.add(new Parent()); // ✅ OK - Parent is exactly Parent
46+
familyList.add(child); // ✅ OK - Child is subtype of Parent
47+
// familyList.add(grandparent); // ❌ NO - Grandparent is not assignable to Parent
48+
49+
// Can only READ as Object (safest common type)
50+
Object obj = familyList.get(0); // ✅ OK - everything is Object
51+
// Parent p = familyList.get(0); // ❌ NO - could be List<Grandparent>
52+
// Child c = familyList.get(0); // ❌ NO - definitely wrong
53+
}
54+
55+
public void acceptYoungerGenerations(List<? extends Parent> familyList) {
56+
// Cannot ADD anything except null
57+
// familyList.add(grandparent); // ❌ NO - cannot add to ? extends
58+
// familyList.add(new Parent()); // ❌ NO - cannot add to ? extends
59+
// familyList.add(child); // ❌ NO - cannot add to ? extends
60+
familyList.add(null); // ✅ OK - null is allowed
61+
62+
// Can READ as Parent or higher in hierarchy
63+
Parent p = familyList.get(0); // ✅ OK - could be Parent or Child
64+
Grandparent gp = familyList.get(0); // ✅ OK - Parent extends Grandparent
65+
// Child c = familyList.get(0); // ❌ NO - could be just Parent, not Child
66+
}
67+
}
68+
```
69+
70+
### Why This Works
71+
- **`? super Parent`**: List could be `List<Parent>` or `List<Grandparent>`
72+
- **Safe to write**: Parent/Child can go into either list type
73+
- **Unsafe to read**: Don't know if it's Parent or Grandparent, so can only read as Object
74+
75+
- **`? extends Parent`**: List could be `List<Parent>` or `List<Child>`
76+
- **Unsafe to write**: Don't know exact type, so can't add anything safely
77+
- **Safe to read**: Whatever comes out is at least a Parent
78+
79+
**💡 Learning Tip:**
80+
- **`? super T`** = "I accept T and its parents" (write T, read Object)
81+
- **`? extends T`** = "I contain T and its children" (read T, write nothing)
82+
83+
**Q:** In `List<? super Parent> family`, why can't you read the result as `Parent`?
84+
**A:** Because the list could actually be `List<Grandparent>`, and reading a Grandparent as Parent would be unsafe downcasting.
3085

3186

3287
## 🃏 Deque Stack vs Queue Operations
@@ -164,4 +219,4 @@ defaults.forEach((k, v) -> userPrefs.merge(k, v, (old, new_) -> old));
164219
**Q:** What happens when you call merge() with a key that doesn't exist in the map?
165220
**A:** The new value is simply inserted (put), and the merge function is not called since there's no existing value to merge with.
166221

167-
---
222+
---

0 commit comments

Comments
 (0)