Understanding Wildcards in Java Generics
Table of Contents
- Introduction
- Understanding Wildcards in Java Generics
- Code Explanation: Handling Wildcards in Java Generics
- Output and Use Cases
- Conclusion
1. Introduction
Wildcards in Java Generics provide flexibility when dealing with parameterized types, allowing code to handle unknown types more effectively. In this article, we will explore the use of wildcards in Java Generics, focusing on the differences between the ? extends
and ? super
wildcards. We will also analyze a code example that demonstrates how wildcards can be applied in practical scenarios.
Key Points:
- Importance of wildcards in managing different types in collections.
- Overview of when to use
? extends
and? super
for handling generics.
2. Understanding Wildcards in Java Generics
Wildcards in Java generics provide a means to handle parameterized types, allowing developers to write more flexible and reusable code. There are two primary types of wildcards:
- Upper-bounded Wildcard (
? extends T
): This wildcard is used when you want to work with types that are subclasses of a given type. It allows reading values but restricts adding new values. - Lower-bounded Wildcard (
? super T
): This wildcard is used when you want to work with types that are superclasses of a given type. It allows adding values but restricts reading them as a specific type.
Wildcard Type | Usage | Example |
---|---|---|
? extends T |
Allows reading values of type T or its subclasses, but prevents writing | List<? extends Number> |
? super T |
Allows writing values of type T or its superclasses, but prevents reading | List<? super Integer> |
3. Code Explanation: Handling Wildcards in Java Generics
We will now break down the provided Java code, which demonstrates the use of the ? super
wildcard in a method that accepts a list of Vehicle
or any of its superclasses.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package org.studyeasy; import java.util.ArrayList; import java.util.List; class Vehicle { private int id; public Vehicle(int id) { this.id = id; } @Override public String toString() { return "Vehicle{id=" + id + '}'; } } class Car extends Vehicle { private String model; public Car(int id, String model) { super(id); this.model = model; } @Override public String toString() { return "Car{model='" + model + "'} " + super.toString(); } } public class Main { public static void main(String[] args) { List<Vehicle> list = new ArrayList<>(); list.add(new Vehicle(1)); list.add(new Vehicle(2)); list.add(new Vehicle(3)); list.add(new Vehicle(4)); list.add(new Car(5, "S40")); Main.display(list); } public static void display(List<? super Vehicle> list) { for (Object data : list) { System.out.println(data); } } } |
Key Concepts and Terminology
- Class Vehicle: A simple class with an id field and an overridden toString() method for displaying the vehicle’s information.
- Class Car: A subclass of Vehicle, which introduces an additional model field and overrides the toString() method to include the car’s model and vehicle ID.
- Method display(List<? super Vehicle>): This method accepts a list of Vehicle or its superclasses using the ? super Vehicle wildcard. The method iterates over the list and prints each element. Here, ? super Vehicle ensures that any object in the list can be treated as a Vehicle.
Detailed Explanation:
- Creating Objects: The main() method creates a list of Vehicle objects and adds several instances of Vehicle and Car. Since Car is a subclass of Vehicle, it can be added to the list of Vehicle.
- Calling the display() Method: The display() method takes a list parameter using the wildcard ? super Vehicle, which ensures that the method can accept any list that holds Vehicle objects or any supertype of Vehicle.
- Printing the List: Inside the display() method, we loop over the list using an enhanced for loop. Since the type is ? super Vehicle, we iterate over the elements as Object types and print them.
4. Output and Use Cases
Output of the Program
1 2 3 4 5 |
Vehicle{id=1} Vehicle{id=2} Vehicle{id=3} Vehicle{id=4} Car{model='S40'} Vehicle{id=5} |
This output shows that both Vehicle
and Car
objects can be stored in the same list, and the display()
method can print them, demonstrating the flexibility provided by wildcards.
When to Use Wildcards
Scenario | Use Case |
---|---|
You want to read data from a list of objects that are all instances of a certain type or its subclasses | Use ? extends |
You want to write data into a list of objects that are instances of a certain type or its superclasses | Use ? super |
5. Conclusion
Wildcards in Java Generics are a powerful tool for handling collections of objects with varying types while maintaining type safety. By understanding when to use ? extends
and ? super
, developers can write more flexible, reusable code that works seamlessly with collections.