泛型,即 "参数化类型",将类型参数化,能够用在类,接口,方法上。swift
与 Java 同样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。数组
声明一个泛型类:安全
class Box<T>(t: T) { var value = t }
建立类的实例时咱们须要指定类型参数: ide
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) }
定义泛型类型变量,能够完整地写明类型参数,若是编译器能够自动推定类型参数,也能够省略类型参数。code
Kotlin 泛型函数的声明与 Java 相同,类型参数要放在函数名的前面:对象
un <T> boxIn(value: T) = Box(value) // 如下都是合法语句 val box4 = boxIn<Int>(1) val box5 = boxIn(1) // 编译器会进行类型推断
在调用泛型函数时,若是能够推断出类型参数,能够省略泛型参数。blog
如下实例建立了泛型函数 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):
若是一个泛型类型中存在多个类型参数, 那么每一个类型参数均可以单独的投射. 好比, 若是类型定义为interface Function<in T, out U> , 那么能够出现如下几种星号投射:
注意: 星号投射与 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 }