kotlin作为一种高级语言,也提供了泛型,它的泛型比Java更为灵活
一、泛型类
1.定义泛型类
定义泛型类和Java差不多
代码语言:javascript复制class Magic<T>(_item: T) {
var subOject: T = _item
}
data class Boy(var name: String, var age: Int)
data class Dog(var age: Int)
fun main() {
println(Magic(Boy("danny", 15)).subOject)
println(Magic(Dog(15)).subOject)
}
结果: Boy(name=danny, age=15) Dog(age=15)
二、泛型函数
1.泛型参数也可以用于函数
代码语言:javascript复制class Magic<T>(_item: T) {
var subOject: T = _item
var available: Boolean = false
fun getItem(): T? {
//available为true,返回泛型类型对象subOject
return subOject.takeIf { available }
}
}
data class Boy(var name: String, var age: Int)
fun main() {
val magic = Magic(Boy("danny", 15))
magic.available = true
println(magic.getItem())
}
2.多个泛型参数的函数
代码语言:javascript复制class Magic<T>(_item: T) {
var subOject: T = _item
var available: Boolean = false
fun <R> getItem(funp: (T) -> R): R? {
//available为true,返回泛型类型对象R
return funp(subOject).takeIf { available }
}
}
data class Boy(var name: String, var age: Int)
data class Man(var name: String, var age: Int)
fun main() {
val magic = Magic(Boy("danny", 15))
magic.available = true
//boy变成man
val man = magic.getItem {
Man(it.name, it.age.plus(10))
}
println(man)
}
三、泛型类型约束
1.如果想要对传递的泛型作约束,可以指定泛型的父类
代码语言:javascript复制//指定父类
class Magic<T : Human>(_item: T) {
var subOject: T = _item
var available: Boolean = false
}
open class Human(var age: Int)
2.如果想要放入多个实例,使用vararg关键字
代码语言:javascript复制class Magic<T : Human>(vararg _items: T) {
var subOject: Array<out T> = _items
var available: Boolean = false
}
3.使用[]操作符取值,也可以自己重载get函数
代码语言:javascript复制class Magic<T : Human>(vararg _items: T) {
var subOject: Array<out T> = _items
var available: Boolean = false
fun <R> getItem(index: Int, funp: (T) -> R): R? {
if (index > subOject.size - 1) return null
//available为true,返回泛型类型对象R
return funp(subOject[index]).takeIf { available }
}
operator fun get(index: Int): T? {
return subOject[index].takeIf { available }
}
}
//父类
open class Human(var age: Int)
class Boy(var name: String, _age: Int) : Human(_age)
class Man(var name: String, _age: Int) : Human(_age)
fun main() {
val magic = Magic(Boy("danny", 15))
magic.available = true
//boy变成man
val man = magic.getItem(0) {
Man(it.name, it.age.plus(10))
}
println("${man?.name} ${man?.age}")
}
4.out
out修饰泛型,表示该泛型对象可以赋值给父类
代码语言:javascript复制class Product<out T : Human>(val product: T) {
fun getItem(): T? = product
}
//父类
open class Human(var age: Int)
class Boy(var name: String, _age: Int) : Human(_age)
class Man(var name: String, _age: Int) : Human(_age)
fun main() {
//泛型是Human,传入的是Boy,Human的子类
val boy: Product<Human> = Product(Boy("danny", 15))
println(boy.getItem())
}
结果: com.aruba.mykotlinapplication.Boy@3cd1a2f1
5.in
in修饰泛型,表示该泛型对象可以赋值给子类
代码语言:javascript复制class Consume<in T : Human>() {
fun cousume(item: T) {
println(item)
}
}
//父类
open class Human(var age: Int)
open class Boy(var name: String, _age: Int) : Human(_age)
class Man(_name: String, _age: Int) : Boy(_name, _age)
fun main() {
//泛型为Boy类型
val man: Consume<Boy> = Consume()
//传入的是Boy的父类Man
man.cousume(Man("danny", 15))
}
结果: com.aruba.mykotlinapplication.Man@3cd1a2f1
而Java中泛型只能使用对应的泛型,没有继承关系
6.reified
kotlin也不允许对泛型作类型检查,当我们想要知道泛型参数具体是哪个类型时,可以使用reified关键字修饰 reified必须和inline配合使用,原因是编译的时候,编译器就需要知道我们传入的类型,只不过代码写成了泛型而已
代码语言:javascript复制class Magic {
inline fun <reified T : Human> getBoy(backUp: () -> T): T {
//随机取一个
val human = listOf(
Boy("danny", 15),
Man("jack", 25)
).shuffled().first()
println(human)
//如果和backup函数返回参数的类型相同,直接返回
return if (human is T) {
human
} else {//否则返回backup函数调用结果
backUp()
}
}
}
open class Human()
class Boy(var name: String, var age: Int) : Human()
class Man(var name: String, var age: Int) : Human()
fun main() {
val magic = Magic()
println(magic.getBoy { Boy("danny", 15) })
}
随机到不是Boy型变量的结果: com.aruba.mykotlinapplication.Man@3f99bd52 com.aruba.mykotlinapplication.Boy@4f023edb 随机到Boy型变量的结果: com.aruba.mykotlinapplication.Boy@3f99bd52 com.aruba.mykotlinapplication.Boy@3f99bd52