Wildcards Summary
Wildcard Types
- Represented by
?
- Three types of wildcards:
- Upper Bounded:
<? extends Type>
- Lower Bounded:
<? super Type>
- Unbounded:
<?>
- Upper Bounded:
Upper Bounded Wildcards
- Accepts type and its subtypes
- Used for reading from structure
- Example:
void printShapes(List<? extends Shape> shapes) { for (Shape s : shapes) { System.out.println(s.getArea()); } }
Lower Bounded Wildcards
- Accepts type and its supertypes
- Used for writing to structure
- Example:
void addCircles(List<? super Circle> list) { list.add(new Circle()); list.add(new Circle(1.0)); }
PECS Principle
- Producer Extends, Consumer Super
- Use extends for input (reading)
- Use super for output (writing)
- Example:
// Producer (extends) - reading from source void copyFromSource(List<? extends Shape> source) { Shape s = source.get(0); // OK } // Consumer (super) - writing to dest void copyToDest(List<? super Circle> dest) { dest.add(new Circle()); // OK }
Unbounded Wildcards
- Represented by
<?>
- Used when actual type doesn't matter
- Example:
void printList(List<?> list) { for (Object o : list) { System.out.println(o); } }
Wildcard Capture
- Compiler captures unknown type
- Used in helper methods
- Example:
public void swap(List<?> list, int i, int j) { swapHelper(list, i, j); // helper method } private <T> void swapHelper(List<T> list, int i, int j) { T temp = list.get(i); list.set(i, list.get(j)); list.set(j, temp); }
Best Practices
- Use PECS principle
- Prefer wildcards over type parameters
- Use unbounded wildcards for Object methods
- Document wildcard usage
- Consider readability vs flexibility
- Test with different type hierarchies