Kotlin-泛型

源自:碼上開(kāi)學(xué)-Kotlin的泛型

kotlin的in和out對(duì)應(yīng)的是
java中帶上界和下界的通配符蝗砾?號(hào)阐污。
【in】 等價(jià)于java中的【? super】
【out】 等價(jià)于java中的【 ? extends】

List<TextView> textviews = new ArrayList<Button>(); // ERROR

以上會(huì)報(bào)錯(cuò)雹顺!不能把子類(lèi)的List對(duì)象賦值給父類(lèi)List的引用避诽。
這是java泛型的一種性質(zhì):covariance(協(xié)變)呐籽。

covariance(協(xié)變)

源自數(shù)學(xué)中的一種概念盏浇。
子類(lèi)的泛型類(lèi)型也屬于泛型類(lèi)型的子類(lèi)变丧。
你聲明一個(gè)父類(lèi)的List,我給你賦值一個(gè)子類(lèi)的List對(duì)象也是可以的绢掰。
但是java的泛型不具備這種性質(zhì)痒蓬。
原因:java泛型在編譯時(shí)的類(lèi)型擦除童擎,由于有類(lèi)型擦除的存在,為了保證類(lèi)型安全攻晒,java給泛型設(shè)置了這種限制顾复。

TextView[] textviews = new Button[10];

在java中用數(shù)組中做類(lèi)似的事情是不會(huì)報(bào)錯(cuò)的。
這是因?yàn)閿?shù)組并沒(méi)有在編譯時(shí)擦除類(lèi)型鲁捏。

但是有這種需求怎么辦芯砸?

使用通配符【? extends】即可。

List<? extends TextView> textViews = new ArrayList<Button>();

這種寫(xiě)法雖然解除了賦值的限制给梅,但是會(huì)增加另一個(gè)限制:
在使用這個(gè)引用的時(shí)候假丧,不能調(diào)用它的參數(shù)包含①類(lèi)型參數(shù)的方法。
[注①:類(lèi)型參數(shù)就是<>里面的東西]


也不能給它的包含類(lèi)型參數(shù)的字段賦值动羽,除了空值包帚。
只能用它不能修改它。

使用場(chǎng)景:

當(dāng)你遇到【只想使用曹质,不需要修改】的情況婴噩,來(lái)讓本來(lái)不具covariance性質(zhì)的java支持covariance,以此來(lái)擴(kuò)大變量或參數(shù)的接收范圍羽德。

public void printTexts(List<? extends TextView> textViews){
  for(TextView textView: textViews){
    Log.e(TAG,textView.getText());
  }
}
List<Button> buttons = ...
printTexts(buttons);

contravariant(逆變)

與之相對(duì)的還有【? super】几莽,它可以讓你把父類(lèi)的泛型類(lèi)型對(duì)象賦值給子類(lèi)的泛型類(lèi)型聲明,叫逆變或者反變宅静。
使用它是附加的限制和【? extends】相反章蚣,在使用這種變量的時(shí)候,不能調(diào)用返回值包含類(lèi)型參數(shù)的方法姨夹。

List<? super Button> textViews = new ArrayList<TextView>();
...
Button button = textViews.get(0); //報(bào)錯(cuò)O舜埂!磷账!

錯(cuò)誤:

public void addTextView(List<TextView> textViews){
  TextView textView = ...;
  textViews.add(textView);
}
...

List<View> views = new ArrayList<>();
addTextView(views);//報(bào)錯(cuò)G吐佟!逃糟!

正確:只希望有一個(gè)能承接這個(gè)TextView的List吼鱼。

public void addTextView(List<? super TextView> textViews){
  TextView textView = ...;
  textViews.add(textView);
}
...
List<View> views = new ArrayList<>();
addTextView(views);

PECS法則

Producer extends, Consumer super

Kotlin中的泛型

//java:
List<? extends TextView> textViews;
List<? super Button> textViews;
//kotlin
var textViews : List<out TextView>
var textViews : List<in TextView>

out:這個(gè)變量只用來(lái)輸出,不用來(lái)輸入绰咽,只能讀菇肃,不能寫(xiě)。
in:只能用來(lái)輸入取募,不能用來(lái)輸出琐谤,只能寫(xiě),不能讀玩敏。

kotlin的out和in不只可以用在變量和參數(shù)的聲明里斗忌,還可以直接用在泛型類(lèi)型聲明時(shí)的類(lèi)型參數(shù)上质礼。它表示我的這個(gè)類(lèi)型就只能用來(lái)輸出或只能用來(lái)輸入。什么意思织阳?說(shuō)白就是几苍,它的作者根據(jù)它的功能判斷出它所有的使用場(chǎng)景都是只能用來(lái)輸出的或者只能用來(lái)輸入的。

interface Producer<out T>{
  fun producer(): T
}
interface Consumer<in T>{
  fun consume(product: T)
}

為了避免我在每個(gè)使用的位置都給變量或者參數(shù)寫(xiě)上in或out這么麻煩(以下寫(xiě)法)陈哑,那么就直接在類(lèi)型創(chuàng)建的地方寫(xiě)上就一勞永逸了(以上寫(xiě)法),這其實(shí)是個(gè)簡(jiǎn)便寫(xiě)法伸眶。

val aProducer: Porducer<out A> = ...
val a = aProducer.produce(); 
...
val bProducer: Porducer<out B> = ...
val b = bProducer.produce();

在類(lèi)型聲明的時(shí)候就加上out或in惊窖,就表示你對(duì)這個(gè)類(lèi)型的定位就是只用來(lái)產(chǎn)出或者消費(fèi)。什么時(shí)候用厘贼!取決你對(duì)這個(gè)類(lèi)的定位界酒!

kotlin還可以在類(lèi)型聲明的時(shí)候用【*】來(lái)填寫(xiě)類(lèi)型參數(shù)。術(shù)語(yǔ)叫Unbounded Wildcard嘴秸,即沒(méi)有上界和下界的意思毁欣。

//kotlin:
var textViews:List<*>
|| 等價(jià)于
var textViews:List<out Any>
//java:
List<?> textViews;
|| 等價(jià)于
List<? extends Object> textViews;

如果你的類(lèi)型聲明里已經(jīng)有了out或者in,那么這個(gè)限制在變量聲明時(shí)也依然存在岳掐。

interface Counter<out T : Number>{
  fun count():T
}
...
var counter : Counter<*> = ...
|| 實(shí)際效果是??
var counter : Counter<out Number> = ...

多重上界

java里泛型聲明的時(shí)候可以通過(guò)extends設(shè)置上界凭疮,注意,這個(gè)是類(lèi)型聲明的上界串述,不是【? extends】执解,這個(gè)上界可以設(shè)置成多重的,用【&】連接纲酗,而在kotlin里衰腌,上界的設(shè)置從extends變成了【:】,多重上界寫(xiě)法要把類(lèi)型從尖括號(hào)里拿出來(lái)寫(xiě)觅赊,并在前面加where關(guān)鍵字右蕊。只是把java的多重上界換了個(gè)寫(xiě)法而已。

//java
class Monster<T extends Animal & Food>{
    ...
}
//kotlin
class Monster<T> where T : Animal , T : Food{
  ...
}

reified

java泛型里的類(lèi)型參數(shù)(就是那個(gè)T)吮螺,它并不是真正的類(lèi)型饶囚,而是一個(gè)代號(hào),所以不能把它當(dāng)做一個(gè)普通的類(lèi)型來(lái)用规脸,比如不能在方法里檢查一個(gè)對(duì)象是不是T的實(shí)例坯约。但在kotlin里可以加reified解除這種限制。不過(guò)reified自身有個(gè)限制莫鸭,只能用來(lái)inline函數(shù)上
java:

<T> void printIfTypeMatch(Object item){
  if(item instanceof T){//報(bào)錯(cuò)D重ぁ!被因!
    TLog.e(item) 
  }
}

kotlin:

inline fun <reified T> printIfTypeMatchI(item: Any){
  if(item is T){
    println(item)
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卿拴,一起剝皮案震驚了整個(gè)濱河市衫仑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堕花,老刑警劉巖文狱,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異缘挽,居然都是意外死亡瞄崇,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)壕曼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)推溃,“玉大人仇穗,你說(shuō)我怎么就攤上這事瓢喉∶祓校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵轧飞,是天一觀(guān)的道長(zhǎng)衅鹿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)过咬,這世上最難降的妖魔是什么大渤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮掸绞,結(jié)果婚禮上兼犯,老公的妹妹穿的比我還像新娘。我一直安慰自己集漾,他們只是感情好切黔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著具篇,像睡著了一般纬霞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驱显,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天诗芜,我揣著相機(jī)與錄音,去河邊找鬼埃疫。 笑死伏恐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的栓霜。 我是一名探鬼主播翠桦,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了销凑?” 一聲冷哼從身側(cè)響起丛晌,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斗幼,沒(méi)想到半個(gè)月后澎蛛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜕窿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年谋逻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桐经。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斤贰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出次询,到底是詐尸還是另有隱情,我是刑警寧澤瓷叫,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布屯吊,位于F島的核電站,受9級(jí)特大地震影響摹菠,放射性物質(zhì)發(fā)生泄漏盒卸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一次氨、第九天 我趴在偏房一處隱蔽的房頂上張望蔽介。 院中可真熱鬧,春花似錦煮寡、人聲如沸虹蓄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)薇组。三九已至,卻和暖如春坐儿,著一層夾襖步出監(jiān)牢的瞬間律胀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工貌矿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炭菌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓逛漫,卻偏偏與公主長(zhǎng)得像黑低,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子酌毡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • 泛型 泛型(Generic Type)簡(jiǎn)介 通常情況的類(lèi)和函數(shù),我們只需要使用具體的類(lèi)型即可:要么是基本類(lèi)型玛荞,要么...
    Tenderness4閱讀 1,419評(píng)論 4 2
  • 建議先閱讀我的上一篇文章 -- Java 泛型 和 Java 泛型一樣娇掏,Kotlin 泛型也是 Kotlin 語(yǔ)言...
    JohnnyShieh閱讀 6,500評(píng)論 1 26
  • 本博文主要講解一些Kotlin泛型的問(wèn)題,中間會(huì)對(duì)比穿插Java泛型勋眯。 1. 泛型類(lèi)型參數(shù) 1.1 形式 我們使用...
    24K男閱讀 18,445評(píng)論 4 11
  • 轉(zhuǎn)載文章婴梧,出處: https://blog.kotliner.cn/2017/06/26/kotlin-gener...
    _10_01_閱讀 693評(píng)論 0 0
  • Kotlin 中也有泛型的概念,和 Java 中的類(lèi)似客蹋,但又不盡相同塞蹭,一起來(lái)認(rèn)識(shí) Kotlin 中的泛型吧。 一讶坯、...
    SheHuan閱讀 28,431評(píng)論 7 24