Java Generics - Bounded Type Parameters

Introduction

Bounded type parameters in Java Generics allow you to restrict the types that can be used as type arguments in a generic class, interface, or method. This ensures that the generic type is a subtype of a specific type or implements a specific interface, providing more control and type safety in your generic code.

Table of Contents

  1. What are Bounded Type Parameters?
  2. Upper Bounded Type Parameters
  3. Lower Bounded Type Parameters
  4. Multiple Bounds
  5. Example Programs
  6. Conclusion

1. What are Bounded Type Parameters?

Bounded type parameters restrict the types that can be used as type arguments. There are two types of bounds in Java Generics:

  • Upper Bound: Specifies that the type parameter must be a subtype of a specific type.
  • Lower Bound: Specifies that the type parameter must be a supertype of a specific type.

2. Upper Bounded Type Parameters

Upper bounded type parameters restrict the type parameter to be a specific type or its subclasses. The extends keyword is used to define an upper bound.

Syntax:

class ClassName<T extends SuperClass> {
    // Class body
}

Example:

public class UpperBoundedExample {
    // Generic method with upper bounded type parameter
    public static <T extends Number> void printDoubleValue(T value) {
        System.out.println(value.doubleValue());
    }

    public static void main(String[] args) {
        printDoubleValue(10);       // Integer
        printDoubleValue(3.14);     // Double
        printDoubleValue(5.67f);    // Float
    }
}

Output:

10.0
3.14
5.670000076293945

Explanation:

  • The printDoubleValue method accepts any type that extends Number.
  • It prints the double value of the passed argument.

3. Lower Bounded Type Parameters

Lower bounded type parameters restrict the type parameter to be a specific type or its supertypes. The super keyword is used to define a lower bound.

Syntax:

class ClassName<T super SubClass> {
    // Class body
}

Example:

import java.util.List;
import java.util.ArrayList;

public class LowerBoundedExample {
    // Generic method with lower bounded type parameter
    public static void addNumbers(List<? super Integer> list) {
        for (int i = 1; i <= 5; i++) {
            list.add(i);
        }
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        addNumbers(numberList);
        System.out.println("Number List: " + numberList);
    }
}

Output:

Number List: [1, 2, 3, 4, 5]

Explanation:

  • The addNumbers method accepts a list that can hold Integer objects or any of its supertypes (Number in this case).
  • It adds integers 1 to 5 to the list.

4. Multiple Bounds

A type parameter can have multiple bounds. A type parameter with multiple bounds must follow this syntax: <T extends A & B & C>. Note that a class must come first, followed by interfaces.

Syntax:

class ClassName<T extends ClassA & InterfaceB & InterfaceC> {
    // Class body
}

Example:

interface Printable {
    void print();
}

class Document {
    public void show() {
        System.out.println("Showing document");
    }
}

class Report extends Document implements Printable {
    @Override
    public void print() {
        System.out.println("Printing report");
    }
}

public class MultipleBoundsExample {
    // Generic method with multiple bounds
    public static <T extends Document & Printable> void process(T item) {
        item.show();
        item.print();
    }

    public static void main(String[] args) {
        Report report = new Report();
        process(report);
    }
}

Output:

Showing document
Printing report

Explanation:

  • The process method accepts any type that extends Document and implements Printable.
  • It calls the show and print methods on the passed argument.

5. Example Programs

Example 1: Upper Bounded Type Parameter in Generic Class

Example:

class Box<T extends Number> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

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

public class UpperBoundedGenericClassExample {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>();
        intBox.setValue(100);
        System.out.println("Integer Value: " + intBox.getValue());
        System.out.println("Double Value: " + intBox.getDoubleValue());

        Box<Double> doubleBox = new Box<>();
        doubleBox.setValue(123.45);
        System.out.println("Double Value: " + doubleBox.getValue());
        System.out.println("Double Value: " + doubleBox.getDoubleValue());
    }
}

Output:

Integer Value: 100
Double Value: 100.0
Double Value: 123.45
Double Value: 123.45

Example 2: Lower Bounded Type Parameter in Method

Example:

import java.util.List;
import java.util.ArrayList;

public class LowerBoundedGenericMethodExample {
    public static void addValues(List<? super Number> list) {
        list.add(1);
        list.add(2.5);
        list.add(3.14f);
    }

    public static void main(String[] args) {
        List<Object> objList = new ArrayList<>();
        addValues(objList);
        System.out.println("Object List: " + objList);

        List<Number> numberList = new ArrayList<>();
        addValues(numberList);
        System.out.println("Number List: " + numberList);
    }
}

Output:

Object List: [1, 2.5, 3.14]
Number List: [1, 2.5, 3.14]

6. Conclusion

Bounded type parameters in Java Generics provide greater control over the types used as arguments in generic classes, methods, and interfaces. They ensure type safety and allow you to define constraints on the type parameters. Upper bounds restrict the type to a specific class or its subclasses, while lower bounds restrict the type to a specific class or its supertypes. Multiple bounds allow a type parameter to extend multiple classes and interfaces, adding further flexibility.

By understanding and using bounded type parameters, you can create more robust and flexible generic code in Java.

Happy coding!

Comments