Kotlin 五 泛型 枚举
Posted qiangge-python
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 五 泛型 枚举相关的知识,希望对你有一定的参考价值。
一 泛型
泛型,即 "参数化类型",将类型参数化,可以用在类,接口,方法上。
与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
声明一个泛型类:
class Box<T>(t: T) var value = t
创建类的实例时我们需要指定类型参数:
val box: Box<Int> = Box<Int>(1) // 或者 val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box<Int>。
以下实例向泛型类 Box 传入整型数据和字符串
class Box<T>(t : T) var value = t fun main(args: Array<String>) var boxInt = Box<Int>(10) var boxString = Box<String>("Runoob") println(boxInt.value) println(boxString.value)
定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。
Kotlin 泛型函数的声明与 Java 相同,类型参数要放在函数名的前面:
un <T> boxIn(value: T) = Box(value) // 以下都是合法语句 val box4 = boxIn<Int>(1) val box5 = boxIn(1) // 编译器会进行类型推断
在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:
fun main(args: Array<String>) val age = 23 val name = "runoob" val bool = true doPrintln(age) // 整型 doPrintln(name) // 字符串 doPrintln(bool) // 布尔型 fun <T> doPrintln(content: T) when (content) is Int -> println("整型数字为 $content") is String -> println("字符串转换为大写:$content.toUpperCase()") else -> println("T 不是整型,也不是字符串")
泛型约束
我们可以使用泛型约束来设定一个给定参数允许使用的类型。
Kotlin 中使用 : 对泛型的类型上限进行约束。
最常见的约束是上界(upper bound):
fun <T : Comparable<T>> sort(list: List<T>) // ……
Comparable 的子类型可以替代 T。 例如:
sort(listOf(1, 2, 3)) // OK。Int 是 Comparable<Int> 的子类型 sort(listOf(HashMap<Int, String>())) // 错误:HashMap<Int, String> 不是 Comparable<HashMap<Int, String>> 的子类型
默认的上界是 Any?。
对于多个上界约束条件,可以用 where 子句:
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String> where T : CharSequence, T : Comparable<T> return list.filter it > threshold .map it.toString()
型变
Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。
声明处型变
声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。
使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型:
// 定义一个支持协变的类 class Runoob<out A>(val a: A) fun foo(): A return a fun main(args: Array<String>) var strCo: Runoob<String> = Runoob("a") var anyCo: Runoob<Any> = Runoob<Any>("b") anyCo = strCo println(anyCo.foo()) // 输出 a
in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型:
// 定义一个支持逆变的类 class Runoob<in A>(a: A) fun foo(a: A) fun main(args: Array<String>) var strDCo = Runoob("a") var anyDCo = Runoob<Any>("b") strDCo = anyDCo
星号投射
有些时候, 你可能想表示你并不知道类型参数的任何信息, 但是仍然希望能够安全地使用它. 这里所谓"安全地使用"是指, 对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。
对于这个问题, Kotlin 提供了一种语法, 称为 星号投射(star-projection):
- 假如类型定义为 Foo<out T> , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper ,Foo<> 等价于 Foo<out TUpper> . 它表示, 当 T 未知时, 你可以安全地从 Foo<> 中 读取TUpper 类型的值.
- 假如类型定义为 Foo<in T> , 其中 T 是一个反向协变的类型参数, Foo<> 等价于 Foo<inNothing> . 它表示, 当 T 未知时, 你不能安全地向 Foo<> 写入 任何东西.
- 假如类型定义为 Foo<T> , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper , 对于读取值的场合, Foo<*> 等价于 Foo<out TUpper> , 对于写入值的场合, 等价于 Foo<in Nothing> .
如果一个泛型类型中存在多个类型参数, 那么每个类型参数都可以单独的投射. 比如, 如果类型定义为interface Function<in T, out U> , 那么可以出现以下几种星号投射:
- Function<*, String> , 代表 Function<in Nothing, String> ;
- Function<Int, *> , 代表 Function<Int, out Any?> ;
- Function<, > , 代表 Function<in Nothing, out Any?> .
注意: 星号投射与 Java 的原生类型(raw type)非常类似, 但可以安全使用
二 枚举类
枚举类最基本的用法是实现一个类型安全的枚举。
枚举常量用逗号分隔,每个枚举常量都是一个对象。
enum class Color RED,BLACK,BLUE,GREEN,WHITE
枚举初始化
每一个枚举都是枚举类的实例,它们可以被初始化:
enum class Color(val rgb: Int) RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF)
默认名称为枚举字符名,值从0开始。若需要指定值,则可以使用其构造函数:
enum class Shape(value:Int) ovel(100), rectangle(200)
枚举还支持以声明自己的匿名类及相应的方法、以及覆盖基类的方法。如:
enum class ProtocolState WAITING override fun signal() = TALKING , TALKING override fun signal() = WAITING ; abstract fun signal(): ProtocolState
如果枚举类定义任何成员,要使用分号将成员定义中的枚举常量定义分隔开
使用枚举常量
Kotlin 中的枚举类具有合成方法,允许遍历定义的枚举常量,并通过其名称获取枚举常数。
EnumClass.valueOf(value: String): EnumClass // 转换指定 name 为枚举值,若未匹配成功,会抛出IllegalArgumentException EnumClass.values(): Array<EnumClass> // 以数组的形式,返回枚举值
获取枚举相关信息:
val name: String //获取枚举名称 val ordinal: Int //获取枚举值在所有枚举数组中定义的顺序
enum class Color RED,BLACK,BLUE,GREEN,WHITE fun main(args: Array<String>) var color:Color=Color.BLUE println(Color.values()) println(Color.valueOf("RED")) println(color.name) println(color.ordinal)
自 Kotlin 1.1 起,可以使用 enumValues<T>()
和 enumValueOf<T>()
函数以泛型的方式访问枚举类中的常量 :
enum class RGB RED, GREEN, BLUE inline fun <reified T : Enum<T>> printAllValues() print(enumValues<T>().joinToString it.name ) fun main(args: Array<String>) printAllValues<RGB>() // 输出 RED, GREEN, BLUE
以上是关于Kotlin 五 泛型 枚举的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin泛型 ③ ( 泛型 out 协变 | 泛型 in 逆变 | 泛型 invariant 不变 | 泛型逆变协变代码示例 | 使用 reified 关键字检查泛型参数类型 )
Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )
Kotlin扩展函数 ① ( 扩展函数简介 | 为 Any 超类定义扩展函数 | private 私有扩展函数 | 泛型扩展函数 | 标准函数 let 函数是泛型扩展函数 )