🌐 العربية
11 Lesson 4 of 5

Generic Interfaces — Comparable<T>

See how interfaces use generics to enforce type-safe contracts

Comparable<T> Type Safety String vs Date Interface Contract

1 Interfaces Can Be Generic Too

We have seen generic classes in Lesson 2 and generic methods in Lesson 3. Now let us see that interfaces can also be generic. In fact, you have already used a generic interface without realizing it!

Just like classes, interfaces can have type parameters. The syntax is exactly the same — you place the type parameter in angle brackets right after the interface name:

Generic Interface Syntax
public interface InterfaceName<T> { T doSomething(T input); void process(T item); }
Key Syntax
The pattern interface Name<T> declares a generic interface. The type parameter T can then be used throughout the interface as a placeholder for any type. When a class implements this interface, it specifies the actual type.

2 Remember Comparable? (Without Generics)

Remember the Comparable interface from Module 9 (Interfaces)? Before Java 5, it looked like this:

Comparable.java — Before Java 5 (no generics)
// Before Java 5 — no generics public interface Comparable { int compareTo(Object o); }

The compareTo method takes Object as its parameter. That means you can compare anything with anything — a String with a Date, an Integer with a Circle. The compiler cannot stop you.

Problem Comparing Apples with Oranges

The Dangerous Code
String name = "Ali"; Date today = new Date(); // Both String and Date implement Comparable // So this compiles fine: int result = name.compareTo(today); // Comparing String with Date?!
Runtime Disaster!
This compiles without any error! The compiler sees Object and says "OK, that's fine." But at runtime, comparing a String with a Date makes no sense — this will throw a ClassCastException! The program crashes, and you only discover the bug when a user reports it.

3 Comparable with Generics

Starting with Java 5, the Comparable interface was redesigned using generics. Let us see the new version:

Comparable.java — Java 5+ (with generics)
// Java 5+ — with generics public interface Comparable<T> { int compareTo(T o); }

Now T is the type parameter. When a class implements Comparable<String>, the compareTo method only accepts String. No more Object — the compiler knows the exact type!

Example How String Implements Comparable<String>

String.java (simplified)
// String implements Comparable<String> public final class String implements Comparable<String> { @Override public int compareTo(String o) { // Compare this string with another String only } }

Notice that compareTo now takes String — not Object. The generic type parameter T has been replaced with the concrete type String.

Safe Usage The Compiler Protects You

Type-Safe Comparison
String name1 = "Ali"; String name2 = "Sara"; int result = name1.compareTo(name2); // String vs String — OK! Date today = new Date(); // name1.compareTo(today); // COMPILE ERROR! // Error: incompatible types: Date cannot be converted to String
Error Caught at Compile Time!
The error is caught at compile time! The generics spell checker prevents us from comparing a String with a Date. The compiler says: "No, you declared Comparable<String>, so you can only compare with String."

4 Side-by-Side Comparison

Let us put the old and new approaches side by side so you can see the difference clearly:

BEFORE — No Generics
Comparable c = "Ali"; // Compiles fine... c.compareTo(new Date()); // ...but CRASHES at runtime! // ClassCastException
AFTER — With Generics
Comparable<String> c = "Ali"; // COMPILE ERROR! c.compareTo(new Date()); // Error caught BEFORE running // Safe and sound
The Pattern
Without generics: the error hides until runtime. With generics: the compiler catches it immediately. This is the same theme we have seen throughout this module — generics move errors from runtime to compile time.

5 Creating Your Own Generic Interface

You are not limited to using Java's built-in generic interfaces. You can create your own! Let us build a simple Container<T> interface that defines a contract for storing and retrieving items of any type.

Step 1 Define the Generic Interface

Container.java
public interface Container<T> { void add(T item); T get(int index); int size(); }

Step 2 Implement the Interface

SimpleList.java
public class SimpleList<T> implements Container<T> { private Object[] items = new Object[100]; private int count = 0; @Override public void add(T item) { items[count++] = item; } @Override @SuppressWarnings("unchecked") public T get(int index) { return (T) items[index]; } @Override public int size() { return count; } }

Notice that SimpleList<T> passes its own type parameter T to Container<T>. This means the implementing class remains generic — the user decides the type when creating a SimpleList object.

Step 3 Use It with Type Safety

Main.java
SimpleList<String> names = new SimpleList<>(); names.add("Ali"); names.add("Sara"); String first = names.get(0); // No casting needed! // names.add(42); // COMPILE ERROR! Only String allowed
Behind the Scenes
This is exactly how Java's own ArrayList<E> works internally! The ArrayList class implements the List<E> interface, which is a generic interface. Now you understand the power behind it.
Two Ways to Implement a Generic Interface

1. Keep it generic: class SimpleList<T> implements Container<T> — the class stays generic, and the user picks the type later.

2. Fix the type: class StringList implements Container<String> — the class locks in a specific type. Every method uses String directly.

6 Key Takeaways

  • 1 Interfaces can be generic, just like classes: interface Name<T>
  • 2 When implementing, specify the type: implements Comparable<String>
  • 3 Generic interfaces enforce type-safe contracts — the compiler checks that both sides of the contract agree on the types
  • 4 Comparable<T> prevents comparing incompatible types — no more String vs Date mistakes
  • 5 Java's built-in interfaces (Comparable, Iterable, List, etc.) all use generics
  • 6 You can create your own generic interfaces to build reusable, type-safe abstractions
← Lesson 3: Generic Methods Lesson 5: Type Erasure →
Code Block Theme