最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Kotlin 泛型詳解及簡(jiǎn)單實(shí)例

 更新時(shí)間:2017年06月05日 10:33:19   作者:行云間  
這篇文章主要介紹了 Kotlin 泛型詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下

 Kotlin 泛型詳解

概述

一般類和函數(shù),只能使用具體的類型:要么是基本類型,要么是自定義的類。如果要編寫可以應(yīng)用于多種類型的代碼,這種刻板的約束對(duì)代碼的限制很大。而OOP的多態(tài)采用了一種泛化的機(jī)制,在SE 5種,Java引用了泛型。泛型,即“參數(shù)化類型”。一提到參數(shù),最熟悉的就是定義方法時(shí)有形參,然后調(diào)用此方法時(shí)傳遞實(shí)參。那么參數(shù)化類型怎么理解呢?顧名思義,就是將類型由原來(lái)的具體的類型參數(shù)化,類似于方法中的變量參數(shù),此時(shí)類型也定義成參數(shù)形式(可以稱之為類型形參),然后在使用/調(diào)用時(shí)傳入具體的類型(類型實(shí)參)。

在Kotlin中,依然可以使用泛型,解耦類與函數(shù)與所用類型之間的約束,甚至是使用方法都與Java一致。

泛型類

聲明一個(gè)泛型類

class Box<T>(t: T) {
  var value = t
}

通常, 要?jiǎng)?chuàng)建這樣一個(gè)類的實(shí)例, 我們需要指定類型參數(shù):

val box: Box<Int> = Box<Int>(1)

但是, 如果類型參數(shù)可以通過(guò)推斷得到, 比如, 通過(guò)構(gòu)造器參數(shù)類型, 或通過(guò)其他手段推斷得到, 此時(shí)允許省略類型參數(shù):

val box = Box(1) // 1 的類型為 Int, 因此編譯器知道我們創(chuàng)建的實(shí)例是 Box&lt;Int> 類型

泛型函數(shù)

泛型函數(shù)與其所在的類是否是泛型沒(méi)有關(guān)系。泛型函數(shù)使得該函數(shù)能夠獨(dú)立于其所在類而產(chǎn)生變化。在<Thinking in Java>有這么一句話:無(wú)論何時(shí)只要你能做到,你就應(yīng)該盡量使用泛型方法,也就是說(shuō)如果使用泛型方法可以取代將整個(gè)類泛型化,那么就應(yīng)該只使用泛型方法,因?yàn)樗梢允故虑楦靼?。這種泛型使用思想,在Kotlin中依然可以延續(xù)。

下面我們聲明了一個(gè)泛型函數(shù)doPrintln,當(dāng)T是一個(gè)Int類型時(shí),打印其個(gè)位的值;如果T是String類型,將字母全部大寫輸出;如果是其他類型,打印“T is not Int and String”。

fun main(args: Array<String>) {
  val age = 23
  val name = "Jone"
  val person = true

  doPrintln(age) // 打?。?
  doPrintln(name) // 打印:JONE
  doPrintln(person) // 打?。篢 is not Int and String
}

fun <T> doPrintln(content: T) {

  when (content) {
    is Int -> println(content % 10) 
    is String -> println(content.toUpperCase())
    else -> println("T is not Int and String")
  }
}

注:

  1. 類型參數(shù)放在函數(shù)名稱之前。
  2. 如果在調(diào)用處明確地傳入了類型參數(shù), 那么類型參數(shù)應(yīng)該放在函數(shù)名稱 之后。如果不傳入?yún)?shù)類型,編譯器會(huì)根據(jù)傳入的值自動(dòng)推斷參數(shù)類型。

擦除的神秘之處

下面我們先看一段代碼:

class Box<T>(t : T) {
  var value = t
}


fun main(args: Array<String>) {
  var boxInt = Box<Int>(10)
  var boxString = Box<String>("Jone")

  println(boxInt.javaClass) // 打?。篶lass com.teaphy.generic.Box
  println(boxString.javaClass) // 打印:class com.teaphy.generic.Box
}

現(xiàn)聲明了一個(gè)泛型類Box<T>,在不同的類型的類型在行為方面肯定不一樣,但是在我們獲取其所在類時(shí),我們只是得到了“class com.teaphy.generic.Box”。在這里我們不得不面對(duì)一個(gè)殘酷的現(xiàn)實(shí):在泛型內(nèi)部,無(wú)法獲得任何有關(guān)泛型參數(shù)類型的信息。

不管是Java還是Kotlin,泛型都是使用擦除來(lái)實(shí)現(xiàn)的,這意味著當(dāng)你在使用泛型時(shí),任務(wù)具體的類型信息都被擦除的,你唯一知道的就是你再使用一個(gè)對(duì)象。比如,Box<String>和Box<Int>在運(yùn)行時(shí)是想的類型,都是Box的實(shí)例。在使用泛型時(shí),具體類型信息的擦除是我們不不懂得不面對(duì)的,在Kotlin中也為我們提供了一些可供參考的解決方案:

  • 類型協(xié)變
  • 類型投射
  • 泛型約束

類型協(xié)變

在類型聲明時(shí),使用協(xié)變注解修飾符(in或者out)。于這個(gè)注解出現(xiàn)在類型參數(shù)的聲明處, 因此我們稱之為聲明處的類型變異。如果在使用泛型時(shí),使用了該類型編譯了會(huì)有什么效果呢?

假設(shè)我們有一個(gè)泛型接口Source<in T, out R>, 其中T由協(xié)變注解in修飾,R由協(xié)變注解Out修飾.

internal interface Source<in T, out R> {
  fun mapT(t: T): Unit
  fun nextR(): R
}
  • in T: 來(lái)確保Source的成員函數(shù)只能消費(fèi)T類型,而不能返回T類型
  • out R:來(lái)確保Source的成員函數(shù)只能返回R類型,而不能消費(fèi)R類型

從上面的解釋中,我們可以清楚的知道了協(xié)變注解in和out的用意,其實(shí)際上是定義了類型參數(shù)在該類或者接口的用途,是用來(lái)消費(fèi)的還是用來(lái)返回的,對(duì)其做了相應(yīng)的限定。

類型投射

上面我們已經(jīng)了解到了協(xié)變注解in和out的用意,下面我們將會(huì)用in和out,做一件有意義的事,看下面代碼

fun copy(from: Array<out String>, to: Array<Any>) {
  // ...
}

fun fill(dest: Array<in String>, value: String) {
  // ...
}

對(duì)于copy函數(shù)中中,from的泛型參數(shù)使用了協(xié)變注解out修飾,意味著該參數(shù)不能在該函數(shù)中消費(fèi),也就是說(shuō)在該函數(shù)中禁止對(duì)該參數(shù)進(jìn)行任何操作。

對(duì)于fill函數(shù)中,dest的泛型參數(shù)使用了協(xié)變注解in修飾,Array<in String>與Java的 Array<? super String> 相同, 也就是說(shuō), 你可以使用CharSequence數(shù)組,或者 Object 數(shù)組作為 fill() 函數(shù)的參數(shù)

這種聲明在Kotlin中稱為類型投射(type projection),類型投射的主要用于對(duì)參數(shù)做了相對(duì)因的限定,避免了對(duì)該參數(shù)類的不安全操作。

星號(hào)投射

有些時(shí)候, 你可能想表示你并不知道類型參數(shù)的任何信息, 但是仍然希望能夠安全地使用它. 這里所謂”安全地使用”是指, 對(duì)泛型類型定義一個(gè)類型投射, 要求這個(gè)泛型類型的所有的實(shí)體實(shí)例, 都是這個(gè)投射的子類型.

對(duì)于這個(gè)問(wèn)題, Kotlin 提供了一種語(yǔ)法, 稱為 星號(hào)投射(star-projection):

  1. 假如類型定義為 Foo<out T> , 其中 T 是一個(gè)協(xié)變的類型參數(shù), 上界(upper bound)為 TUpper ,Foo<> 等價(jià)于 Foo<out TUpper> . 它表示, 當(dāng) T 未知時(shí), 你可以安全地從 Foo<> 中 讀取TUpper 類型的值.
  2. 假如類型定義為 Foo<in T> , 其中 T 是一個(gè)反向協(xié)變的類型參數(shù), Foo<> 等價(jià)于 Foo<inNothing> . 它表示, 當(dāng) T 未知時(shí), 你不能安全地向 Foo<> 寫入 任何東西.
  3. 假如類型定義為 Foo<T> , 其中 T 是一個(gè)協(xié)變的類型參數(shù), 上界(upper bound)為 TUpper , 對(duì)于讀取值的場(chǎng)合, Foo<*> 等價(jià)于 Foo<out TUpper> , 對(duì)于寫入值的場(chǎng)合, 等價(jià)于 Foo<in Nothing> .

如果一個(gè)泛型類型中存在多個(gè)類型參數(shù), 那么每個(gè)類型參數(shù)都可以單獨(dú)的投射. 比如, 如果類型定義為interface Function<in T, out U> , 那么可以出現(xiàn)以下幾種星號(hào)投射:

  1. Function<*, String> , 代表 Function<in Nothing, String> ;
  2. Function<Int, *> , 代表 Function<Int, out Any?> ;
  3. Function<, > , 代表 Function<in Nothing, out Any?> .

注意: 星號(hào)投射與 Java 的原生類型(raw type)非常類似, 但可以安全使用

泛型約束

對(duì)于一個(gè)給定的類型參數(shù), 所允許使用的類型, 可以通過(guò)泛型約束(generic constraint) 來(lái)限制。

上界

最常見的約束是 上界(upper bound):

fun <T : Comparable<T>> sort(list: List<T>) {
  // ...
}

冒號(hào)之后指定的類型就是類型參數(shù)的 上界(upper bound): 對(duì)于類型參數(shù) T , 只允許使用 Comparable<T>的子類型. 比如:

sort(listOf(1, 2, 3)) // 正確: Int 是 Comparable&lt;Int> 的子類型
sort(listOf(HashMap<Int, String>())) // 錯(cuò)誤: HashMap<Int, String> 不是
Comparable<HashMap<Int, String>> 的子類型

如果沒(méi)有指定, 則默認(rèn)使用的上界是 Any? . 在定義類型參數(shù)的尖括號(hào)內(nèi), 只允許定義唯一一個(gè)上界. 如果同一個(gè)類型參數(shù)需要指定多個(gè)上界, 這時(shí)就需要使用單獨(dú)的 where 子句:

fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T> where T : Comparable,
T : Cloneable {
  return list.filter { it > threshold }.map { it.clone() }
}

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Spring MVC Controller返回值及異常的統(tǒng)一處理方法

    Spring MVC Controller返回值及異常的統(tǒng)一處理方法

    這篇文章主要給大家介紹了關(guān)于Spring MVC Controller返回值及異常的統(tǒng)一處理方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Spring Boot產(chǎn)生環(huán)形注入的解決方案

    Spring Boot產(chǎn)生環(huán)形注入的解決方案

    這篇文章主要介紹了Spring Boot產(chǎn)生環(huán)形注入的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊的方法詳解

    SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊的方法詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊功能,文中示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定參考價(jià)值,需要的可以參考一下
    2022-05-05
  • 利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)

    利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)

    利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-10-10
  • Java中synchronized鎖升級(jí)的過(guò)程

    Java中synchronized鎖升級(jí)的過(guò)程

    本文主要介紹了Java中synchronized鎖升級(jí)的過(guò)程,synchronized相對(duì)于早期的synchronized做出了優(yōu)化,從以前的加鎖就是重量級(jí)鎖優(yōu)化成了有一個(gè)鎖升級(jí)的過(guò),下文詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • Java應(yīng)用程序開發(fā)學(xué)習(xí)之static關(guān)鍵字應(yīng)用

    Java應(yīng)用程序開發(fā)學(xué)習(xí)之static關(guān)鍵字應(yīng)用

    今天小編就為大家分享一篇關(guān)于Java應(yīng)用程序開發(fā)學(xué)習(xí)之static關(guān)鍵字應(yīng)用,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • SpringMVC請(qǐng)求數(shù)據(jù)詳解講解

    SpringMVC請(qǐng)求數(shù)據(jù)詳解講解

    Spring MVC 是 Spring 提供的一個(gè)基于 MVC 設(shè)計(jì)模式的輕量級(jí) Web 開發(fā)框架,本質(zhì)上相當(dāng)于 Servlet,Spring MVC 角色劃分清晰,分工明細(xì),本章來(lái)講解SpringMVC如何請(qǐng)求數(shù)據(jù)
    2022-07-07
  • java編程創(chuàng)建型設(shè)計(jì)模式工廠方法模式示例詳解

    java編程創(chuàng)建型設(shè)計(jì)模式工廠方法模式示例詳解

    這篇文章主要為大家介紹了java編程創(chuàng)建型設(shè)計(jì)模式之工廠方法模式的創(chuàng)建及案例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • java基礎(chǔ)之?dāng)?shù)組常用操作總結(jié)(必看篇)

    java基礎(chǔ)之?dāng)?shù)組常用操作總結(jié)(必看篇)

    下面小編就為大家?guī)?lái)一篇java基礎(chǔ)之?dāng)?shù)組常用操作總結(jié)(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java后端登錄實(shí)現(xiàn)返回token

    Java后端登錄實(shí)現(xiàn)返回token

    本文主要介紹了Java后端登錄實(shí)現(xiàn)返回token,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評(píng)論

墨脱县| 民乐县| 漳州市| 青龙| 岗巴县| 横山县| 新干县| 英德市| 开阳县| 南部县| 万州区| 西宁市| 昭通市| 宜城市| 宜都市| 福建省| 唐海县| 岫岩| 叶城县| 赫章县| 揭阳市| 庆元县| 突泉县| 喜德县| 丽水市| 宁陕县| 内乡县| 银川市| 鄂伦春自治旗| 高密市| 柯坪县| 西峡县| 平凉市| 黄龙县| 刚察县| 沂源县| 保靖县| 吉隆县| 阿坝| 陈巴尔虎旗| 金华市|