用泛型來宣告 Box , T 代表泛型型態 , 泛型型態 T 之後可以用其他實際型別代替他
class Box<T>(t: T) {
var value = t
}
如果要建立 Generics class 的 object 需要給予 type (實際型別)
val box = Box<Int>(1)
如果可以從 傳入的 參數判斷 type 可以被省略
val box = Box(1)
限制 泛型的實際型別 只能是 特定 supertype 或者是他的 subtype
下面限制 泛型 型別 只能是 Number 或者是他的 subtype
class Box<T:Number>(t: T) {
var value = t
}
Int 形態和 Double 形態是Number的 subtype,會被接受
Box(1)
Box(0.5)
當你傳入一個 String type 的 value 會報錯
Type mismatch: inferred type is String but Number was expected
Box("1")
當泛型型態 沒有 in 或 out 修飾符時 , 可以說一但有一個型別取代了泛型 T, 這個類別就只能接受這型別
例如 定義下面泛型 類別
class Retailer <T>{
fun sell():T{
}
}
下面變數 類型 泛型型別 Cat , 只能接受 同樣 泛型型別 Cat 的物件
val catRetailer: Retailer <Cat> = Retailer <Cat>
錯誤,不能接受 泛型型別 Dog 的物件
val catRetailer: Retailer <Cat> = Retailer <Dog>
兩種情形可以用 out , 也就是 不能 進入 一個類別
val 變數 型別(只讀不可寫), var 不可
T 泛型型別 是 回傳的型別 , 不可以是傳入參數 的 型別 (參數 是 val 可以)
定義一個變數 Cat Retailer , 泛型型別 是 Cat , 將一個同樣是泛型型別 Cat Retailer class object 傳給他是可以的
val catRetailer: Retailer <Cat> = Retailer <Cat>
下面是無法編譯的 , 泛型型別 是 Pet 的 Retailer class , 只能接受 同樣 泛型型別 Pet
的 Retailer class 物件 , 並不能接受 泛型型別 為 subtype(cat)的 Retailer class 物件
val petRetailer: Retailer <Pet> = Retailer <Cat>
可以藉由 out 修飾符 , 也就是協變 , 來達成上面
interface Retailer < out T>{
fun sell():T
}
這樣我們就可以把 subtype 泛型型別 的 物件 , 傳遞給 同類別 的 supertype 泛型型別 物件
val petRetailer: Retailer <Pet> = Retailer <Cat>
下面情形可以用 in , 也就是 進入 一個類別 的位置
定義 Vet class , treat 傳入的參數的型別 為 T
class Vet<T:Pet>{
fun treat(t:T){
}
}
下面我們定義兩個 Vet 類型的 變數 , 泛型型別 Cat Vet class 物件 , 可以傳遞給 同樣泛型 的類別 , 但 泛型型別 Pet Vet class 物件 則無法傳遞
val Vet1: Vet<Cat> = Vet<Cat>()
val Vet2 : Vet<Cat> = Vet<Pet>()
如果要達成上面可以在 Vet class 泛型 加上 in 修飾符,也就是共變 , 讓泛型 supertype 取代 subtype
class Vet<in T:Pet>{
fun treat(t:T){
}
}
這樣下面這段就可以編譯了
val Vet2 : Vet<Cat> = Vet<Pet>()
如果我們並沒有 讓所有 subtype 的 泛型型別 都接受 subtype 的 泛型型別,我們可
在特定的地方 再加上 in 修飾符
Vet Class 去除 in 修飾符
這樣就限制了 Vet 的 泛型型別 , 讓型別 是不變的 , 只能接受特定型別
class Vet< T:Pet>{
fun treat(t:T){
}
}
下面 泛型型別 限定 Cat,就不能接受其他型別(不管是他的 subtype 或者是 supertype)的物件
val Vet2 : Vet<Cat> = Vet<Pet>()
在 需要的地方 加上 in 修飾符
class Medical<T:Pet> (var vet : Vet<in T>){
}
這樣我們可以將 泛型型別 為 Pet 的 Vet 物件 傳給 泛型型別 為 Cat Medical 類別
val hospital: Medical <Cat> = Medical(Vet<Pet>())