Generic InterfacesS2C Home « Generic Interfaces

With generics we can create our own generic interfaces which allow us to create generalized interfaces, same interface rules apply, with all the type safety that generics gives us.

When creating your own generic types it is best practice to use pneumonics for the formal type parameter rather than multiple letters.

Following is a simple generic interface and class so you can see how we can create a generic interface and implement it. We are using T as the placeholder for our formal type parameter in this instance, which you can think of as a pneumonic for Type. For a collections example we would use the E pneumonic for Element.


package com.server2client;

/*
  Simple generic interface that accepts any object
*/
interface SimpleGenericInterface<T> { 

    // Implementation will show object type
    void showObjectType();
}

In the overridden showObjectType() method below we are using the getClass() method of Object to get the actual Class type which we chain to getName(), which is a method of the Class object, which can be found in the java.lang package, then print this to the console. Notice how we use the T formal type parameter within the declaration and constructor.


package com.server2client;

/*
  Simple generic class that implements SimpleGenericInterface
*/
public class SimpleGenericInterfaceImpl<T> implements SimpleGenericInterface<T> {

    // Generic object declaration
    private final T genericObj;

    // Pass reference to object of type T to our constructor
    public SimpleGenericInterfaceImpl(T genericObj) {
        this.genericObj = genericObj;
    }

    // Output object type of T to console
    public void showObjectType() {
        System.out.println("Object type of T is " + genericObj.getClass().getName());
    }
}

Now we need to write a test class to show how we can pass various objects to our SimpleGenericInterfaceImpl class:


package com.server2client;

/*
  Test our SimpleGenericClass class that accepts any object
*/
public class TestSimpleGenericInterfaceImpl {

    public static void main(String[] args) {

        // Test the SimpleGenericInterfaceImpl using a String object
        SimpleGenericInterfaceImpl<String> genStringObj = new SimpleGenericInterfaceImpl<>("ab");
        genStringObj.showObjectType();
    
        // Test the SimpleGenericInterfaceImpl using an Integer object
        SimpleGenericInterfaceImpl<Integer> genIntegerObj = new SimpleGenericInterfaceImpl<>(1);
        genIntegerObj.showObjectType();
    
        // Test the SimpleGenericInterfaceImpl using a Double object
        SimpleGenericInterfaceImpl<Double> genDoubleObj = new SimpleGenericInterfaceImpl<>(1.2);
        genDoubleObj.showObjectType();
    }
}

Running the TestSimpleGenericInterfaceImpl class in IntelliJ produces the following output:

Run generic class
Screenshot 1. Running the TestSimpleGenericInterfaceImpl class.

So from the screenshot you can see that our TestSimpleGenericClass class works with the various objects passed to it replacing the T formal type parameter placeholder with the actual type parameter of the object passed. We mentioned ealier that the compiler inserts the casts required to make generics work when we run our bytecode. What we haven't mentioned yet is that generic code is implemented by erasure, which means that generic code enforces type constraints only at compile time. The element type information is erased in the runtime bytecode, which is how legacy code can freely interoperate with generic code. So the point here is that at runtime there is only one version of the SimpleGenericInterfaceImpl class that works through the casts inserted automatically by the compiler into the runnable bytecode.

Generally if a class implements a generic interface then that class must be generic as well, so that it takes a type parameter that is passed to the interface. If an actual parameter is used when implementing the interface, then the class doesn't have to be generic. The following code snippet should clarify this:


package com.server2client;

// Following is correct as used above
public class SimpleGenericInterfaceImpl<T> implements SimpleGenericInterface<T> { 

// Following is incorrect as no type specifed for class and formal type parameter specified
public class SimpleGenericInterfaceImpl implements SimpleGenericInterface<T> { 

// Following is fine as actual type specified for implementation, so class is not generic
public class SimpleGenericInterfaceImpl implements SimpleGenericInterface<String> { 

Related Quiz

Generics Quiz 3 - Generics Interfaces Quiz

Lesson 3 Complete

In this lesson we looked at generics interfaces and how to use them.

What's Next?

In the next lesson we look at generic classes.