Industrial Training




Kotlin Generics


Generics are the powerful features that allow to define classes, methods, and properties etc. which can be accessed using different types. The type differences of classes, methods, etc. are checked at compile-time.
The generic type class or method is declared as parameterized type. A parameterized type is an instance of generic type with actual type arguments. The parameterized types are declared using angle brackets <> Generics are mostly used in collections.


Advantage of Generics


Following are the key advantages of using generics:


  • Type-safety: Generic allows to hold only single type of object. Generic does not allow to store other object.
  • Type casting is not required: There is no need to typecast the object.
  • Compile time checking: Generics code is checked at compile time so that it can avoid any problems at runtime.

Let's see a problem without using the generics.
In this example, we create a Person class with primary constructor having single parameter. Now, we want to pass the different type of data in object of Person class (say Int type as Person(30) and String type as Person("40")). The primary constructor of Person class accept Int type Person(30) and regrets String type Person("40"). It generates a compile time error as type mismatch.


class Person (age:Int){  
var age: Int = age  
init {  
this.age= age  
println(age)  
    }  
}  
fun main(args: Array){  
var ageInt: Person = Person(30)  
var ageString: Person = Person("30")// compile time error  
}  

To solve the above problem, we use a generic type class which is a user defined class that accepts different type of parametersin single class.
Let's rewrite the above code using generic type. A class Person of type < T> is a general type class that accepts both Int and String types of parameter.
In other words, the type parameter is a place holder that will be replaced by type argument. It will be replaced when the generic type is instantiated.

class Person(age: T){  
var age: T = age  
init {  
this.age= age  
println(age)  
    }  
}  
fun main(args: Array< String>){  
var ageInt: Person< Int> = Person< Int>(30)  
var ageString: Person< String> = Person< String>("40")  
}  

Output:
30
40

In above example, when the object of Person class is created using type Int as Person< Int>(30) and Person< String>("40"), it replaces the Person class of type T with Int and String respectively.


Syntax of generic class
class_or_interface  

Syntax of generic method
< Type>methodName(parameter: classType< Type>)  

Kotlin generic example


Let's see an example of generic method. In this example, we are accessing the generic method of collection type (ArrayList). For doing this, we create two different objectsof ArrayList class arrayListOf< String>("Ashu","Ajay") and arrayListOf< Float>(10.5f,5.0f,25.5f) of String and Float types respectively. When we call the generic method < T>printValue(list: ArrayList< T>) using printValue(stringList), the type T of method < T>printValue(list: ArrayList< T>)will be replaced by String type. Similarly, when we call the generic method using printValue(floatList), the type T of method < T>printValue(list: ArrayList< T>) will replace by Float type.

fun main(args: Array< String>){  
val stringList: ArrayList< String> = arrayListOf< String>("Ashu","Ajay")  
val s: String = stringList[0]  
println("printing the string value of stringList: $s")  
printValue(stringList)  
val floatList: ArrayList< Float> = arrayListOf< Float>(10.5f,5.0f,25.5f)  
printValue(floatList)     
}  
fun < T>printValue(list: ArrayList){  
    for(element in list){  
println(element)  
    }  
}  

Output:
printing the string value of stringList: Ashu
Ashu
Ajay
10.5
5.0
25.5

Kotlin generic extension function example


As extension function allows to add methods to class without inherit a class or any design pattern.
In this example, we add a method printValue()to ArrayList class of generic type. This method is called form stringList.printValue() and floatList.printValue()of String and Float types respectively. As "this" keyword in extension function represent the current calling instance. When we call the extension function using stringList.printValue(), the this represents stringList instance containing String type values. Similarly, calling the extension function using floatList.printValue(), the this represents floatList instance containing Float type values.


fun main(args: Array< String>){  
val stringList: ArrayList< String> = arrayListOf< String>("Ashu","Ajay")  
stringList.printValue()  
val floatList: ArrayList< Float> = arrayListOf< Float>(10.5f,5.0f,25.5f)  
floatList.printValue()  
}  
fun < T>ArrayList< T>.printValue(){  
    for(element in this){  
println(element)  
    }  
}  

Output:
Ashu
Ajay
10.5
5.0
25.5



Hi I am Pluto.