# 1. 泛型
**泛型**是一種編譯時的安全檢測機制,它允許在定義類、接口、方法時使用類型參數,聲明的類型參數在使用時用具體的類型來替換。泛型的**本質是參數化類型**,也就是說所操作的數據類型被指定為一個參數。其實在之前的小節中也用到過泛型,且其用法和`Java`中基本一致,所以這里就簡略介紹。
# 2. 泛型類
**泛型符號**可以是滿足`Kotlin`命名規則的任意字符,甚至可以是某一個單詞。比如下面的案例:
~~~
data class KotlinDemo<N, A>(var name: N, var age: A) {
override fun toString(): String {
return "KotlinDemo(name=$name, age=$age)"
}
}
fun main() {
var demo = KotlinDemo<String, Int>("張三", 24)
println(demo)
}
~~~
結果:
```
KotlinDemo(name=張三, age=24)
```
至于用在方法和接口上的使用類似,這里就不再繼續給出案例。
# 3. 泛型約束
注意到上面的方式僅僅只是簡單的應用,而實際上還有泛型約束。比如在`Java`中提供了`super`和`extends`關鍵字來進行。在`Kotlin`中類似的可以進行對類型的約束。
- `<? extends類或接口> ` 類比于: `<T:類或接口>`。可以理解為泛型的上界,因為在`Kotlin`中使用`:`來表示繼承關系。
比如下面的案例:
~~~
open class Animal{
var weight = 30
}
// 繼承
class Cat: Animal() {
var name = "Cat"
override fun toString(): String {
return "Cat(name='$name', weight=$weight)"
}
}
class KotlinDemo<T: Animal> (animal: T){
private var demo: T? = null
init {
if(this.demo == null) {
this.demo = animal
}
}
override fun toString(): String {
return "KotlinDemo(demo=$demo)"
}
}
fun main() {
var demo = KotlinDemo<Cat>(Cat())
println(demo)
}
~~~
結果:
```
KotlinDemo(demo=Cat(name='Cat', weight=30))
```
# 4. 協變與逆變
協變與逆變其實是`C#`語言`4.0`以后新增的高級特性,**協變**是將父類變為具體子類,協變類型作為消費者,只能讀取不能寫入,**逆變**是將子類變為具體父類,逆變作為生產者,只能寫入不能讀取。
- **協變**,父類變子類,只能讀取(`out`);
- **逆變**,子類變父類,只能寫入(`in`);
對于`in`和`out`這兩個單詞的簡單理解記憶圖示:

上圖來自視頻:[Kotlin教程](https://www.bilibili.com/video/BV1wf4y1s7TG?p=114)
這么說起來比較抽象,這里直接給出兩個案例。
## 4.1 案例一:逆變
~~~
// 逆變,只寫,作為函數參數
interface Consumer<in T>{
fun consume(item: T)
}
open class Animal
class Cat: Animal()
class KotlinDemo2: Consumer<Animal> {
override fun consume(item: Animal){
}
}
fun main() {
var consumer1: Consumer<Cat> = KotlinDemo2()
}
~~~
## 4.2 案例二:協變
~~~
// 協變,只讀,即僅作為返回值
interface Producer<out T>{
fun produce(): T
}
open class Animal
class Cat: Animal()
class KotlinDemo2: Producer<Animal> {
override fun produce(): Animal{
return Animal()
}
}
class KotlinDemo1: Producer<Cat> {
override fun produce(): Cat {
return Cat()
}
}
fun main() {
var consumer1: Producer<Animal> = KotlinDemo1()
}
~~~
父變子指的是:要求是`Animal`,但是賦值的為子類對象。
# 5. 泛型類型檢查
有時候我們需要對傳入的泛型的類型做一個檢查,而在`Java`中我們通常使用反射來獲取類型進而進行判斷,比如:
~~~
interface B<T>{
T getInstance(T t);
}
public class A<T> implements B<T>{
@Override
public T getInstance(T t) {
if(t.getClass().getName() .equals("com.kotlinLearn.Animal")){
return t;
}
return (T) new Cat();
}
public static void main(String[] args) {
A<Animal> a = new A<>();
Animal instance = a.getInstance(new Cat());
System.out.println(instance.getClass().getName());
}
}
~~~
結果:
```
com.kotlinLearn.Cat
```
而在`Kotlin`中就不需要這么麻煩,可以直接使用關鍵字`inline`和`reified`進行判斷:
~~~
open class Animal
class Cat: Animal()
class B{
inline fun<reified T> getInstance(item: () -> T): T {
val animal = Animal()
return if(animal is T){
animal
} else{
item()
}
}
}
~~~
- Kotlin語言基礎
- Kotlin的簡介
- Kotlin的變量和常見數據類型
- Kotlin的區間
- Kotlin的位運算
- Kotlin的容器
- Kotlin類型檢查
- Kotlin的空值處理
- Kotlin的函數
- Kotlin的類
- Kotlin的委托
- Kotlin的延遲加載
- Kotlin的異常
- Kotlin的Lambda表達式
- Kotlin的高階函數
- Kotlin的標準庫中的高階函數
- Kotlin的泛型
- Kotlin的表達式
- Kotlin的解構
- Kotlin的運算符重載
- Kotlin語言中級
- Kotlin的擴展函數
- Kotlin的擴展屬性
- Kotlin的infix關鍵字
- Kotlin的DSL
- Kotlin的一些注解(和Java互調用)
- Kotlin的lateinit和by lazy
- Kotlin的反射
- Kotlin的匿名接口
- 安卓中的Kotlin
- 數據庫操作Room