Generic Interfaces
TL;DR
- Just like classes, Interfaces can be Generic.
- When a class implements a generic interface, it can either provide a concrete type or remain generic itself.
- Famous examples:
Comparable<T>,List<E>,Callable<V>.
Concept
Generic interfaces allow you to define contracts where the types of inputs or outputs are flexible.
When you implement a generic interface, you have two choices:
- Concrete Implementation: You specify exactly what type the interface should use (e.g.,
class StringSorter implements Sorter<String>). - Generic Implementation: The implementing class itself remains generic, passing its type parameter up to the interface (e.g.,
class MyList<T> implements List<T>).
Examples
// 1. Define a Generic Interface
interface Repository<T> {
void save(T item);
T findById(int id);
}
// 2. Concrete Implementation (Type is specified)
class UserRepository implements Repository<String> {
@Override
public void save(String item) {
System.out.println("Saving User string: " + item);
}
@Override
public String findById(int id) {
return "User_" + id;
}
}
// 3. Generic Implementation (Passes type parameter up)
class GenericRepository<T> implements Repository<T> {
@Override
public void save(T item) {
System.out.println("Saving generic item: " + item);
}
@Override
public T findById(int id) {
return null;
}
}
public class GenericInterfaceExample {
public static void main(String[] args) {
Repository<String> userRepo = new UserRepository();
userRepo.save("Alice");
Repository<Integer> intRepo = new GenericRepository<>();
intRepo.save(42);
}
}
Interview Questions
Q: What happens if you implement a generic interface but don’t specify the type parameter?
A: If you write class MyClass implements Repository, you are using the Raw Type. The compiler will issue a warning, and the type parameter T will default to Object. All methods defined in the interface will now accept and return Object. This defeats the purpose of generics and should be avoided.
Q: Can an interface have multiple generic type parameters?
A: Yes. A prime example is the java.util.Map<K, V> interface, which takes two type parameters: one for the Key and one for the Value. You can define as many parameters as needed, like interface Triplet<A, B, C>.