In this section, we will learn what the Generic Interfaces are and how to use them in Kotlin.
Note: we’re assuming you’re already familiar with the Kotlin Generics.
What is Generic Interface in Java? And How to Declare a Generic Interface in Kotlin?
A generic interface has generic types just like in generic classes and we can use them as the stand-in data type of members of an interface.
The way we create and use a generic type on interfaces is exactly the same as the way we use them in classes.
For example:
interface InterfaceName <T>{…}
Here, the T is a generic type and could be used as the temporal data type for the members of the interface.
Also note that any rule we apply to the generic types in classes, like the way we restrict them, could also be applied to the generic types in interfaces.
For example:
interface InterfaceName<T:Person>{…}
Here, the T type can be either the Person class or any classes that inherit from this class. Hence, we can use the members (like parameters) that used this generic type and invoke the members of the Person class with them.
How to Implement a Generic Interface?
There are two ways to implement a generic interface:
- Applying a generic Interface on a Generic Class
- Applying a generic interface on a non-generic class
1- Implementing a Generic Interface as if it’s a non-generic Interface
The first method, and perhaps the simpler one, is when we have a non-generic class that implements a generic interface! Here, when implementing the generic interface, you need to set the data type for the generic type of that interface explicitly!
This is the syntax:
class ClassName: InterfaceName<data-type>{…}
As you can see, after the interface name, we put a pair of angle brackets and then set the data type within those brackets.
Example: implementing a Generic Interface as Non-Generic Interface
class NonGeneric: MyGenericInterface<String, Int>{…} interface MyGenericInterface<T,E>{ fun printDetails(par1:T,par2:E) } class NonGenericClass:MyGenericInterface<String,Int>{ override fun printDetails(par1:String,par2:Int){ println("The value of the par1 is: $par1 and the value of the par2 is: $par2") } } fun main(){ var nonGen = NonGenericClass() nonGen.printDetails("Omid",100) }
Output:
The value of the par1 is: Omid and the value of the par2 is: 100
Note that the main problem using a non-generic class is that you need to define the data type of the interface right when the target class is implementing it!
This might not be an interesting choice, especially if we don’t know the data type until at runtime!
Now this is where the second method of setting the data type for interfaces comes in! So let’s go and see that now.
2- Implementing a Generic Interface via a Generic Class
The second method of setting the data types of a generic interface is when it’s used with a generic class!
When using a generic interface with a generic class, we can use the generic type name of the class and set them as the data type for the target interface!
This way when we create an object and setting the actual data type for the generic types of the class, these data types will be passed to the target interface as well and hence the generic type names for the interface will also be replaced with real data types!
Alright, let’s see an example to practically see how this method works.
Example: Implementing a Generic Interface via a Generic Class
interface MyGenericInterface<T,E>{ fun printDetails(par1:T,par2:E) } class GenericClass<M, N>:MyGenericInterface<M,N>{ override fun printDetails(par1:M,par2:N){ println("The value of the par1 is: $par1 and the value of the par2 is: $par2") } } fun main(){ var gen = GenericClass<String,Int>() gen.printDetails("Ellen",100) }
Output:
The value of the par1 is: Ellen and the value of the par2 is: 100
As you can see, the GenericClass
has two generic types and we’ve passed these two types as the data type for the interface that it implemented.
Now, when we create an object from the class and set actual data types for these generic types, it will be passed for the generic class as well as the implemented interface.