泛型,即 "參數化類型",將類型參數化,能夠用在類,接口,方法上。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 }