Bounded type parameters expand on the capabilities of the compile time type safety that generics bring.
It does this by allowing us to restrict the

To add bounds, we use the extends keyword followed by the Class or Interface type we want the type parameter to

Simple bounds

In this example, we restrict the type parameter arguments to be either Number or one of its subtypes!

class MyBox<T extends Number> {
	private T value;
	public MyBox(T v) {
		value = v;
	}
	public T get() {
		return value;
	}
	
	public static void main (String[] args) {
		MyBox<Integer> a = new MyBox<>(1);
		MyBox<String> b = new MyBox<>("hehe");
	}
}

Compilation Error!

type argument String is not within bounds of type-variable T MyBox<String> b = new MyBox<>(“hehe”);

Assignment of String to the type parameter of MyBox fails as the type parameter is bounded, meaning the argument must have a ‘is a’ relationship with Number, as defined by <T extends Number>.

Multiple Bounds

abstract class Animal{
	protected int numberOfLimbs;
	public Animal(int n) {
		numberOfLimbs = n;
	}
	
	public static void main(String[] args) {
		// This is fine because Dog has a 'is a' relationship with
		// both Animal and CanBark
		BarkingBox<Dog> a = new BarkingBox<>(new Dog());
		// Whereas, this fails as Cat is not a CanBark
		BarkingBox<Cat> b = new BarkingBox<>(new Cat());
	}
}
 
class BarkingBox<T extends Animal & CanBark> {
	private T value;
	public BarkingBox(T v) {
		value = v;
	}
	public T get() {
		return value;
	}
}
 
interface CanBark {
	String bark();
}
 
class Cat extends Animal {
	public Cat() {
		super(4);
	}
}
 
class Dog extends Animal implements CanBark {
	public Dog() {
		super(4);
	}
	
	@Override
	public String bark() {
		return "woof!";
	}
}

Compilation Error!

type argument Cat is not within bounds of type-variable T BarkingBox<Cat> b = new BarkingBox<>(new Cat());

What’s Next?

java-generic-wildcards