We often use generics in Android development, such as List, Map, Set, Adapter, etc. generics are also supported in Kotlin.
What is generics?
Generics: special types that postpone the type specific work until the object is created or the method is called.
1, Defining generic methods in Kotlin
Defining generics in Kotlin is the same as Java in the following two ways:
- Defined on class
- Defined in function
Examples defined on classes:
class MagicBox<T>(val item: T) { var available = false fun fetch(): T? { return item.takeIf { available } } }
Defined in function
class MagicBox<T>(val item: T) { var available = false /** * Add normal form type in function, similar to Java */ fun <R> fetch(anotherGenericity: (T) -> R): R? { return anotherGenericity(item).takeIf { available } } }
2, Defining constraint generics in Kotlin
Defining constraint generics in Kotlin is similar to defining generics in Java < T extend XXX >, which means that the type specified by generics must be a class of the specified type or a subclass that inherits the specified type class. For example: define a generic class a < T: b > (), and the incoming generic t must be B or a subclass of B. A complete example is as follows:
//Define a constraint generic private class ConstraintMagicBox<T:Human>(item:T){ } //Define a parent class private open class Human(val name: String,val age:Int) //Define a subclass of Human class private class Male(name: String,age: Int):Human(name, age) //Define a subclass of Human class private class Female(name: String,age: Int):Human(name, age) fun main() { //The same type of Human can be passed in val male = ConstraintMagicBox(Male("Jack", 20)) val female = ConstraintMagicBox(Female("Jim", 20)) }
3, Kotlin defines a number of variable parameter generics
This is similar to defining a variable parameter (private void method(int.. num)) for a method in Java. The definition method in Kotlin depends on the keyword * * vararg * *. Ordinary functions and constructors can be used.
Examples are as follows:
private class VarMagicBox<T : VarHuman>(vararg val items: T) { //Get data from items according to the parameters, where the items type is not Array fun fetch(index: Int): T? { return items.getOrNull(0) } //Adding variable parameters to functions fun fetch(vararg indexs: Int):List<T>{ indexs.takeIf { indexs.isNotEmpty() }.run { return items.filterIndexed { index, t -> indexs.contains(index) } } } } private open class VarHuman(val name: String, val age: Int)
4, Modifying generics with in and out in Kotlin
In Java, specify a specific type in the definition of a List. When creating an instance, you can only new instances of this type, and you cannot new instances of subclasses or parent classes,
example:
ArrayList<String> list = new ArrayList<CharSequence>()
perhaps
ArrayList<CharSequence> list = new ArrayList<String>()
These two writing methods are not supported in JAVA. The correct writing method is: ArrayList < string > List = new ArrayList < string > ().
However, support can be achieved in Kotlin.
Of course, the generic examples defined above are not supported, so how can Kotlin support such a writing?
Because Kotlin has two important keywords: in (covariance) and out (inversion)
Let's look at how the following two keywords support the above writing.
The usage is very simple. Let's start with the above example and see how to use it:
//The out decorated generic type only takes the generic type as the return value of the function //Function: let the subclass generic object assign value to the parent generic object interface OutTest<out T>{ fun outTest():T } //in modified generics only take generics as function parameters, and generics cannot be used as return values //A generic object can be assigned to a subclass interface InTest<in T>{ fun inTest(param : T) }
The test code is as follows:
open class Food() open class FastFood():Food() class Hamburg():FastFood() class FastFoodStore() : OutTest<FastFood>{ override fun outTest(): FastFood { println("FastFoodStore ----------") return FastFood() } } class HamburgStore():InTest<FastFood>{ override fun inTest(param: FastFood) { println("HamburgStore-----------") } } fun main() { //Subclass objects can be passed to parent generic objects val food1 : OutTest<Food> = FastFoodStore() //The parent class object can be passed to the child class generic object in val food2 : InTest<Hamburg> = HamburgStore() }
Keyword in and out Usage Summary
There are two main points:
- The generic type modified by out can only be used in the return value of the function, and the generic type modified by in can only be used in the parameters of the function;
- The out modified generic can only assign the subclass generic object to the parent generic object, and the in modified generic can only assign the parent generic object to the subclass generic object, as shown in the figure below;
Welcome to leave a message and learn from each other!
Sample source address kotlin_demo