Advanced Generics

Back

Loading concept...

🎯 Advanced Generics: The Magic Box That Knows What’s Inside

Imagine you have a magical toy box. But this isn’t just any box—it’s a SMART box that only accepts certain toys and always remembers exactly what you put in!


🌟 The Story: The Picky Toy Sorter

Meet Genny the Generics Wizard. She runs a magical toy factory where every box must be labeled perfectly. Today, she’s teaching her apprentices the advanced secrets of her magic boxes.


📦 Bounded Type Parameters: The Box with Rules

What Is It?

Think of a toy box that says: “I only accept toys that can roll!”

A bounded type parameter limits what types can go into your generic. It’s like putting a bouncer at the door of your box.

Real-World Analogy

🎢 Theme Park Height Check: You must be THIS TALL to ride. Same idea—your type must meet certain requirements!

Simple Example

// Only accept things that are Numbers
public class NumberBox<T extends Number> {
    private T value;

    public double getDoubleValue() {
        return value.doubleValue();
    }
}

// ✅ Works: Integer is a Number
NumberBox<Integer> intBox = new NumberBox<>();

// ❌ Error: String is NOT a Number
NumberBox<String> strBox = new NumberBox<>();

Why Use It?

  • You can call methods from the bound type (Number.doubleValue())
  • Compiler catches wrong types immediately
  • Makes your code safer and smarter!

🃏 Wildcards in Generics: The Flexible Card

What Is It?

Sometimes you want a box that says: “I’ll accept any toy, I just won’t add more!”

The wildcard (?) is like a mystery card. It represents “some unknown type.”

The Three Wildcards

graph TD W["Wildcards ?"] --> U["? unbounded"] W --> UB["? extends Type"] W --> LB["? super Type"] U --> |"Any type"| ANY["List of ?"] UB --> |"Type or children"| READ["Read only"] LB --> |"Type or parents"| WRITE["Write only"]

1. Unbounded Wildcard: ?

// I accept a list of ANYTHING
public void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

2. Upper Bounded: ? extends Type

“Give me Type or any of its children”

// Accept Number or any subclass
public double sum(List<? extends Number> nums) {
    double total = 0;
    for (Number n : nums) {
        total += n.doubleValue();
    }
    return total;
}

// ✅ Works with Integer, Double, etc.
sum(Arrays.asList(1, 2, 3));
sum(Arrays.asList(1.5, 2.5));

3. Lower Bounded: ? super Type

“Give me Type or any of its parents”

// Accept Integer or any superclass
public void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

// ✅ Works!
List<Number> nums = new ArrayList<>();
addNumbers(nums);

🎭 Type Erasure: The Disappearing Act

What Is It?

Here’s a secret: Java’s generics are a compile-time trick!

At runtime, List<String> and List<Integer> become just… List. The type info vanishes like magic. This is called type erasure.

Why Does Java Do This?

🕰️ Backward Compatibility: Old Java code (before generics existed) still needs to work!

What Happens?

// What you write:
List<String> names = new ArrayList<>();
names.add("Alice");
String name = names.get(0);

// What Java sees at runtime:
List names = new ArrayList();
names.add("Alice");
String name = (String) names.get(0);

The compiler:

  1. Checks your types at compile time ✅
  2. Removes generic info at runtime 🧹
  3. Adds casts where needed 🔄

Proof of Erasure

List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();

// Both are just "ArrayList" at runtime!
System.out.println(
    strings.getClass() == integers.getClass()
); // true!

🚫 Generic Restrictions: Things You Cannot Do

Generics have some rules. Here are the “No Entry” signs:

1. No Primitive Types

// ❌ WRONG
List<int> numbers;

// ✅ RIGHT - use wrapper class
List<Integer> numbers;

2. No new T()

// ❌ WRONG - Can't create generic object
public <T> void create() {
    T obj = new T(); // Error!
}

3. No new T[]

// ❌ WRONG - Can't create generic array
T[] arr = new T[10]; // Error!

4. No Static Generic Fields

public class Box<T> {
    // ❌ WRONG
    private static T value;
}

5. No instanceof with Generics

// ❌ WRONG
if (obj instanceof List<String>) { }

// ✅ RIGHT
if (obj instanceof List<?>) { }

Memory Trick 🧠

“PANSS”: Primitives, Arrays, New instances, Static fields, inStanceof - all forbidden with type parameters!


🐱 PECS Principle: Producer Extends, Consumer Super

The Golden Rule

This is THE most important rule for wildcards. Memorize it!

PECS = Producer Extends, Consumer Super

What Does It Mean?

graph TD P["PECS Principle"] --> PE["Producer EXTENDS"] P --> CS["Consumer SUPER"] PE --> |"Reading FROM"| R["? extends T"] CS --> |"Writing TO"| W["? super T"]

🎁 Producer = You GET things FROM it

When you read from a collection, use extends:

// I'm GETTING numbers out (producing)
public double sum(List<? extends Number> producer) {
    double total = 0;
    for (Number n : producer) {
        total += n.doubleValue();
    }
    return total;
}

🗑️ Consumer = You PUT things INTO it

When you write to a collection, use super:

// I'm PUTTING integers in (consuming)
public void fill(List<? super Integer> consumer) {
    consumer.add(1);
    consumer.add(2);
    consumer.add(3);
}

Real-World Analogy

🍎 Apple Basket Story:

  • Producer (extends): “Give me any basket that has apples or smaller fruits. I’ll just take them out.”
  • Consumer (super): “Give me any basket that can hold apples or bigger. I’ll put apples in.”

Quick Reference

Scenario Wildcard Why?
Reading items ? extends T Safe to get T
Writing items ? super T Safe to add T
Both read/write Use exact type T Need both!

🎓 Putting It All Together

public class GiftShop<T extends Gift> {
    private List<T> inventory;

    // Producer - reading gifts out
    public void showGifts(List<? extends T> source) {
        for (T gift : source) {
            System.out.println(gift);
        }
    }

    // Consumer - putting gifts in
    public void stockGifts(List<? super T> dest) {
        for (T gift : inventory) {
            dest.add(gift);
        }
    }
}

✨ Key Takeaways

Concept One-Liner
Bounded Types T extends X = T must be X or its child
Wildcards ? = unknown type for flexibility
Type Erasure Generic info vanishes at runtime
Restrictions No primitives, no new T(), no static T
PECS Read = extends, Write = super

🚀 You Did It!

You’ve just unlocked the advanced secrets of Java Generics!

Remember:

  • Bounded types = Bouncers at the door
  • Wildcards = Flexible mystery cards
  • Type erasure = The disappearing act
  • PECS = Producer Extends, Consumer Super

Now go build type-safe, flexible, and powerful code! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.