Bounded type parameters restrict the types that can be used as arguments for a generic type parameter. This is achieved using the extends keyword, allowing you to specify that a type parameter must be a subtype of a particular class or interface (or the class/interface itself). Bounded type parameters enhance type safety and enable access to methods defined in the bounding type.
Syntax
class ClassName<T extends BoundType> { ... }
T is the type parameter.
BoundType is the class or interface that T must extend or implement.
extends is used for both classes and interfaces in this context.Code language: JavaScript (javascript)
Types of Bounded Type Parameters
Upper-Bounded Type Parameter
An upper-bound restricts the type parameter to a specific class/interface or its subtypes.
class NumberBox<T extends Number> {
private T number;
public NumberBox(T number) {
this.number = number;
}
public double getDoubleValue() {
return number.doubleValue(); // Access Number's method
}
public static void main(String[] args) {
NumberBox<Integer> intBox = new NumberBox<>(100);
NumberBox<Double> doubleBox = new NumberBox<>(99.99);
System.out.println(intBox.getDoubleValue()); // Output: 100.0
System.out.println(doubleBox.getDoubleValue()); // Output: 99.99
// NumberBox<String> strBox = new NumberBox<>("Test"); // Compile-time error
}
}
Here...
T must be a Number or its subclass (e.g., Integer, Double).
Methods of Number (e.g., doubleValue()) are accessible on T.Code language: JavaScript (javascript)
Bounding to an Interface
class ComparableBox<T extends Comparable<T>> {
private T item;
public ComparableBox(T item) {
this.item = item;
}
public int compareTo(T other) {
return item.compareTo(other); // Access Comparable's method
}
public static void main(String[] args) {
ComparableBox<String> strBox = new ComparableBox<>("Apple");
System.out.println(strBox.compareTo("Banana")); // Output: -1 (Apple < Banana)
}
}
Here...
T must implement Comparable<T> (e.g., String, Integer).
Methods of Comparable (e.g., compareTo) are accessible.Code language: JavaScript (javascript)
Multiple Bounds
A type parameter can have multiple bounds, combining a class and one or more interfaces using &.
Syntax
class ClassName<T extends ClassName & Interface1 & Interface2> { ... }
The class (if present) must come first, followed by interfaces.
Only one class bound is allowed, but multiple interfaces are permitted.Code language: JavaScript (javascript)
class MyClass<T extends Number & Comparable<T>> {
private T value;
public MyClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public int compareTo(T other) {
return value.compareTo(other);
}
public double doubleValue() {
return value.doubleValue();
}
public static void main(String[] args) {
MyClass<Integer> intBox = new MyClass<>(42);
System.out.println(intBox.compareTo(50)); // Output: -1 (42 < 50)
System.out.println(intBox.doubleValue()); // Output: 42.0
}
}Code language: PHP (php)
Demonstrating Bounded Type Parameters
This program implements a generic Container class for storing and comparing items, a generic utility method for finding the maximum of two comparable items, and a demonstration of bounded type parameters with multiple bounds. The types used are restricted to Number and Comparable to showcase practical constraints.
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
// Generic class with a bounded type parameter
class Container<T extends Number & Comparable<T> & Serializable> {
private T item;
// Constructor
public Container(T item) {
this.item = item;
}
// Get the stored item
public T getItem() {
return item;
}
// Get the double value of the item (from Number)
public double getDoubleValue() {
return item.doubleValue();
}
// Compare with another item (from Comparable)
public int compareTo(T other) {
return item.compareTo(other);
}
// Check if the item is serializable (from Serializable)
public boolean isSerializable() {
return item instanceof Serializable;
}
}
// Utility class with generic methods
class Util {
// Generic method with bounded type parameter to find the maximum
public static <T extends Comparable<T>> T findMax(T item1, T item2) {
return item1.compareTo(item2) >= 0 ? item1 : item2;
}
// Generic method to print a list of numbers
public static <T extends Number> void printNumberList(List<T> list, String label) {
System.out.print(label + ": ");
for (T num : list) {
System.out.print(num + " ");
}
System.out.println();
}
}
public class BoundedTypeDemo {
public static void main(String[] args) {
// Example 1: Using Container with Integer
Container<Integer> intContainer = new Container<>(42);
System.out.println("Integer Container:");
System.out.println("Item: " + intContainer.getItem());
System.out.println("Double Value: " + intContainer.getDoubleValue());
System.out.println("Compared to 50: " + intContainer.compareTo(50)); // Negative if 42 < 50
System.out.println("Is Serializable: " + intContainer.isSerializable());
System.out.println();
// Example 2: Using Container with Double
Container<Double> doubleContainer = new Container<>(99.99);
System.out.println("Double Container:");
System.out.println("Item: " + doubleContainer.getItem());
System.out.println("Double Value: " + doubleContainer.getDoubleValue());
System.out.println("Compared to 100.0: " + doubleContainer.compareTo(100.0)); // Negative if 99.99 < 100.0
System.out.println("Is Serializable: " + doubleContainer.isSerializable());
System.out.println();
// Example 3: Using findMax method
System.out.println("Maximum Examples:");
System.out.println("Max of 10 and 20: " + Util.findMax(10, 20));
System.out.println("Max of 3.14 and 2.71: " + Util.findMax(3.14, 2.71));
System.out.println("Max of 'Apple' and 'Banana': " + Util.findMax("Apple", "Banana"));
System.out.println();
// Example 4: Using printNumberList with bounded lists
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
Util.printNumberList(intList, "Integer List");
Util.printNumberList(doubleList, "Double List");
// Util.printNumberList(Arrays.asList("A", "B"), "String List"); // Compile-time error
// Example 5: Compile-time error demonstration
// Container<String> strContainer = new Container<>("Test"); // Error: String is not a Number
}
}
/*
Integer Container:
Item: 42
Double Value: 42.0
Compared to 50: -8
Is Serializable: true
Double Container:
Item: 99.99
Double Value: 99.99
Compared to 100.0: -1
Is Serializable: true
Maximum Examples:
Max of 10 and 20: 20
Max of 3.14 and 2.71: 3.14
Max of 'Apple' and 'Banana': Banana
Integer List: 1 2 3 4 5
Double List: 1.1 2.2 3.3
*/Benefits of Bounded Type Parameters
- Type Safety: Restricts types to valid ones, preventing errors at compile time.
- Access to Methods: Allows access to methods of the bounding type (e.g., doubleValue() for Number).
- Flexibility: Enables generic code to work with a family of related types (e.g., all Number subclasses).
