泛型
类型参数化,和Java一样,Kotlin也有泛型。省去类型强转的麻烦,也提供了类型安全方面的保障。
1、泛型类
定义带泛型参数的类。
例:
class Type<T>(type: T) {
var type: T = type
get() {
return field
}
set(value) {
field = value
}
}
泛型类Type中的值就会根据实际传入的参数类型
var bool = Type(false)
println(bool.type.javaClass.simpleName)
var str = Type("string")
println(str.type.javaClass.simpleName)
var num: Type<Int> = Type(1)
println(num.type.javaClass.simpleName)
输出结果:
//boolean
//String
//int
注意:
①如果已经将某个变量初始化为一种泛型,就不能再次赋值成其它类型的泛型了:
②创建泛型类型的对象直接使用var关键字即可,Kotlin自动进行类型推断。如果一定要指定变量的类型,必须也要指定泛型的类型:
正确的泛型类型定义语法,加上具体的泛型类型:
var num: Type<Int> = Type(1)
2、泛型方法
方法的参数、返回值也可以是泛型,更加传入参数的值推断实际类型。
例:
定义一个泛型方法:
fun <T> whichType(type: T) {
if (type is String) {
println("String")
} else if (type is Int) {
println("Int")
} else if (type is Boolean) {
println(type)
}
}
传入不同类型的参数,泛型函数根据传入的参数做不同的操作:
whichType(1)
whichType(false)
whichType("what?")
/**
* 输出:
* Int
* false
* String
*/
上面一堆判空方法,能不能简写呢?比如直接简写成:
fun <T> whichType(type: T) {
println(type.javaClass.simpleName)
}
这是不行的,非空才能调用泛型参数的方法
既然需要判空?,判空语法参考《 Kotlin基本语法》,就可以根据传入的参数类型做不同的操作:
fun <T> whichType(type: T) {
println(type?.javaClass?.simpleName)
}
虽然不会提示错误。但是,实际编译运行却会报错:
Error:Kotlin: Type inference failed: Not enough information to infer parameter T in val <T : Any!> Class<T>.simpleName: String!
Please specify it explicitly.
Error:Kotlin: Type parameter bound for T in val <T : Any> T.javaClass: Class<T>
is not satisfied: inferred type T is not a subtype of Any
提示意思是没有足够的信息推断类型T。
3、泛型限定
上面的问题可以很轻松的用泛型限定来解决:
fun <T : Any> whichType(type: T) {
println(type.javaClass.simpleName)
}
但是这样泛型方法传入的泛型又不可以为null
在泛型限定T前加上?,表明该泛型参数可能为null。
fun <T : Any?> whichType(type: T) {
//type可为null
}
看着似乎完美了,是因为还是空方法,加上点调用又警告了和上一节出现一样的情况,因为默认的上界是 Any?,加不加都一样。
那有没有办法呢?还是有的用?:表达式做判空断处理
fun <T : Any?> whichType(type: T) {
println((type ?: 1).javaClass.simpleName)
}
4、协变
Java泛型中有通配符,这里不详细介绍,参考《java泛型通配符详解》。
<T extends View> void painting(T t) {
//T可以是所有继承自View的子类
}
4.1、声明处型变 out
out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型。
例:
class Variance<out T>(val t: T) {
fun variance(): T {
return t
}
}
协变返回
var a = Variance<String>("String")
var b = Variance<Any>("Any")
//可以将a赋值给b,返回类型将协变成为a中的泛型类型String
b = a
4.2、类型投影 in
in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型。
例:
class Projections<in T>( t: T) {
fun projections() {
}
}
输入协变
var a = Projections<String>("String")
var b = Projections<Any>("Any")
a = b
注意:
in和out不能同时使用,两者是互斥的
协变输入只能由泛型宽的转到泛型窄的,反过来不行。
学习资料:
Kotlin 泛型