We often use generics in Android development, such as: List, Map, Set, Adapter, etc., so generics are also supported in Kotlin.
What is generic?
Generics: Defer the work of type definition until when creating an object or calling a method to specify a specific type.
1. Define generic methods in Kotlin
There are two ways to define generics in Kotlin as in Java:
- defined on the class
- Defined in a function
Defined on a class Example:
class MagicBox<T>(val item: T) {
var available = false
fun fetch(): T? {
return item.takeIf { available }
}
}
defined in the function
class MagicBox<T>(val item: T) {
var available = false
/**
* 函数中增加范式类型,类似Java
*/
fun <R> fetch(anotherGenericity: (T) -> R): R? {
return anotherGenericity(item).takeIf { available }
}
}
2. Define constrained generics in Kotlin
The definition of constrained generics in Kotlin < T extend XXX>
is similar to the way Java defines generics, which means that the type specified by the generic must be a class of the specified type or a subclass that inherits the class of the specified type. This sentence is a bit confusing, for example: define a generic type class A<T : B>()
, the incoming generic type T must be B or a subclass of B. A complete example is as follows:
//定义一个约束泛型
private class ConstraintMagicBox<T:Human>(item:T){
}
//定义一个父类
private open class Human(val name: String,val age:Int)
//定义一个Human类的子类
private class Male(name: String,age: Int):Human(name, age)
//定义一个Human类的子类
private class Female(name: String,age: Int):Human(name, age)
fun main() {
//同为Human类型的可传入
val male = ConstraintMagicBox(Male("Jack", 20))
val female = ConstraintMagicBox(Female("Jim", 20))
}
3. Kotlin defines variable parameter generics
This is similar to defining variable parameters ( private void method(int.. num)
) for methods in Java. The definition method in Kotlin uses the keyword ** vararg
**, which can be used for both ordinary functions and constructors.
Examples are as follows:
private class VarMagicBox<T : VarHuman>(vararg val items: T) {
//根据参数从items中获取数据,其中items类型未Array
fun fetch(index: Int): T? {
return items.getOrNull(0)
}
//在函数中增加可变参数
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. Use in and out to modify generics in Kotlin
In defining a List in Java, specify a specific type. When creating an instance, only instances of this type can be new, and instances of subclasses or parent classes cannot be new. For example: or these two ways of writing are not supported
in
ArrayList<String> list = new ArrayList<CharSequence>()
JAVA
ArrayList<CharSequence> list = new ArrayList<String>()
. The correct way of writing is: ArrayList<String> list = new ArrayList<String>()
.
But support can be done in Kotlin .
Of course, the generic examples defined above are also not supported, so how can Kotlin support such a way of writing?
Because there are two important keywords in Kotlin in(协变)
,out(逆变)
let's see how the latter two keywords can support the above-mentioned writing method.
The usage is very simple, let's look at the example first, and see how to use it:
//out修饰的泛型 仅将泛型作为函数返回值
//作用:让子类泛型对象可以赋值给父类泛型对象
interface OutTest<out T>{
fun outTest():T
}
//in修饰的泛型 仅将泛型作为函数参数,泛型无法当做返回值
//作用:让父类泛型对象可以赋值给子类泛型对象
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() {
//子类对象可以传给父类泛型对象 out
val food1 : OutTest<Food> = FastFoodStore()
//父类对象可以传给子类泛型对象 in
val food2 : InTest<Hamburg> = HamburgStore()
}
关键字in、out使用总结
There are two main points:
out
Modified generics can only函数返回值
be used in , andin
modified generics can only函数的参数
be used in ;out
Modified generics can only be used子类泛型对象赋值给父类泛型对象
, andin
modified generics can only be used父类泛型对象赋值给子类泛型对象
, as shown in the figure below;
Welcome to leave a message and learn from each other!
Example source address kotlin_demo