Introduction
A generic interface in Java allows you to define an interface with type parameters, making it more flexible and reusable. Generic interfaces enable you to define methods that can operate on various types while providing compile-time type safety. This guide will cover how to define and use generic interfaces in Java, along with examples to illustrate their usage.
Table of Contents
- What is a Generic Interface?
- Defining a Generic Interface
- Implementing a Generic Interface
- Example: Simple Generic Interface
- Bounded Type Parameters in Generic Interfaces
- Example: Generic Interface with Bounded Type Parameters
- Type Inference with Generic Interfaces
- Restrictions on Generic Interfaces
- Conclusion
1. What is a Generic Interface?
A generic interface is an interface that declares one or more type parameters. These type parameters can be used in the interface's methods, allowing the interface to work with different data types while maintaining type safety.
2. Defining a Generic Interface
A generic interface is defined by placing the type parameter(s) inside angle brackets (<>
) after the interface name.
Syntax:
interface InterfaceName<T> {
// Interface methods
}
3. Implementing a Generic Interface
When a class implements a generic interface, it must either specify the type parameters or remain generic itself.
Implementing a Generic Interface with Specific Type
Example:
interface GenericInterface<T> {
void display(T value);
}
class StringPrinter implements GenericInterface<String> {
@Override
public void display(String value) {
System.out.println("String value: " + value);
}
}
public class GenericInterfaceExample {
public static void main(String[] args) {
StringPrinter printer = new StringPrinter();
printer.display("Hello, Generics!");
}
}
Output:
String value: Hello, Generics!
Implementing a Generic Interface with Generic Type
Example:
interface GenericInterface<T> {
void display(T value);
}
class GenericPrinter<T> implements GenericInterface<T> {
@Override
public void display(T value) {
System.out.println("Value: " + value);
}
}
public class GenericInterfaceExample {
public static void main(String[] args) {
GenericPrinter<String> stringPrinter = new GenericPrinter<>();
stringPrinter.display("Hello, Generics!");
GenericPrinter<Integer> intPrinter = new GenericPrinter<>();
intPrinter.display(123);
}
}
Output:
Value: Hello, Generics!
Value: 123
4. Example: Simple Generic Interface
Example:
interface Pair<K, V> {
K getKey();
V getValue();
}
class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
}
public class GenericInterfaceExample {
public static void main(String[] args) {
Pair<String, Integer> pair = new OrderedPair<>("One", 1);
System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());
Pair<Integer, String> anotherPair = new OrderedPair<>(2, "Two");
System.out.println("Key: " + anotherPair.getKey() + ", Value: " + anotherPair.getValue());
}
}
Output:
Key: One, Value: 1
Key: 2, Value: Two
5. Bounded Type Parameters in Generic Interfaces
You can restrict the types that can be used as type arguments by using bounded type parameters. Bounded type parameters allow you to specify that a type must be a subclass (or implementor) of a specific class (or interface).
Syntax:
interface InterfaceName<T extends SuperClass> {
// Interface methods
}
6. Example: Generic Interface with Bounded Type Parameters
Example:
interface Numeric<T extends Number> {
double getDoubleValue(T value);
}
class NumericImpl<T extends Number> implements Numeric<T> {
@Override
public double getDoubleValue(T value) {
return value.doubleValue();
}
}
public class BoundedGenericInterfaceExample {
public static void main(String[] args) {
Numeric<Integer> intNumeric = new NumericImpl<>();
System.out.println("Double value of Integer: " + intNumeric.getDoubleValue(100));
Numeric<Double> doubleNumeric = new NumericImpl<>();
System.out.println("Double value of Double: " + doubleNumeric.getDoubleValue(123.45));
}
}
Output:
Double value of Integer: 100.0
Double value of Double: 123.45
7. Type Inference with Generic Interfaces
Java's compiler can infer the type parameters of a generic interface from the context in which it is used. This feature is known as type inference.
Example:
interface Displayable<T> {
void display(T value);
}
class DisplayImpl<T> implements Displayable<T> {
@Override
public void display(T value) {
System.out.println("Value: " + value);
}
}
public class TypeInferenceExample {
public static void main(String[] args) {
Displayable<String> stringDisplay = new DisplayImpl<>();
stringDisplay.display("Hello, Generics!");
Displayable<Integer> intDisplay = new DisplayImpl<>();
intDisplay.display(123);
}
}
Output:
Value: Hello, Generics!
Value: 123
8. Restrictions on Generic Interfaces
There are several restrictions on generic interfaces in Java:
-
Cannot Instantiate Generic Types with Primitive Types:
// This is not allowed GenericInterface<int> intObj = new GenericInterface<>();
-
Cannot Create Instances of Type Parameters:
class GenericClass<T> { // This is not allowed // T obj = new T(); }
-
Cannot Declare Static Fields Whose Types are Type Parameters:
class GenericClass<T> { // This is not allowed // static T obj; }
-
Cannot Use Casts or instanceof with Parameterized Types:
class GenericClass<T> { // This is not allowed // if (obj instanceof T) { } // T[] array = (T[]) new Object[10]; }
-
Cannot Create Arrays of Parameterized Types:
// This is not allowed GenericInterface<String>[] stringArray = new GenericInterface<String>[10];
9. Conclusion
Generic interfaces in Java provide a powerful mechanism to define flexible, reusable, and type-safe interfaces. By using type parameters, you can create interfaces that can operate on various types, ensuring type safety and reducing the need for type casting. Bounded type parameters further enhance the flexibility of generic interfaces by allowing you to specify constraints on the types that can be used as arguments.
By understanding and utilizing generic interfaces, you can create more robust and maintainable Java applications.
Happy coding!
Comments
Post a Comment
Leave Comment