亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Kotlin?泛型邊界型變及星投影使用詳解

 更新時間:2022年12月08日 11:20:01   作者:無糖可樂愛好者  
這篇文章主要為大家介紹了Kotlin?泛型邊界型變及星投影使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1.泛型

Android項目開發(fā)過程中普遍會遇到一個問題:adapter的樣式、業(yè)務邏輯很相似,但是需要的數(shù)據(jù)源不是來自一個接口,常規(guī)情況下就要定義多個構造函數(shù)但是這樣就要更改構造函數(shù)的傳參順序或者增加傳參要么就是將他們統(tǒng)一成一個類。但是用泛型就可以這樣解決:

class CommonAdapter<T>(val list: List<T>) : RecyclerView.Adapter<CommonAdapter.ViewHolder>() {
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        TODO("Not yet implemented")
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        TODO("Not yet implemented")
    }
    override fun getItemCount() = list.size
}
//調用CommonAdapter
mBinding.rvTab.adapter = CommonAdapter(listOf("周一","周二","周三"))
mBinding.rvTab.adapter = CommonAdapter(listOf(CommonData("張三"),CommonData("李四"),CommonData("王五")))

可以看到泛型可以很好的解決這個問題。

再舉個例子,電子產品的充電器,在以前充電接口沒有統(tǒng)一的時候每個設備都需要一個單獨的充電器,這樣就很麻煩,下面的代碼就是對這個問題的一種表示

// 手機
class Phone {
    fun charging() {}
}
// 平板
class Pad {
    fun charging() {}
}
//無線耳機
class Headset {
    fun charging() {}
}
//便攜音箱
class Speakers {
    fun charging() {}
}

統(tǒng)一充電器接口后就只需要保留一個充電器即可,這個概念就需要用到泛型了

//統(tǒng)一接口
class UnifiedInterface<T> {
    fun charging(device: T) {}
}
val phone = UnifiedInterface<Phone>()
phone.charging()
val pad = UnifiedInterface<Pad>()
pad.charging()

在統(tǒng)一接口UnifiedInterface中傳入要充電的電子設備就可以了。T代表的就是各種電子設備。

這里要注意的一點是在使用泛型的時候還可以加上邊界

class UnifiedInterface<T: Phone> {
    fun charging(device: T) {}
}

上面的代碼中Phone就是邊界,用【:】這個邊界的聲明就是說只能傳入Phone類或者它的子類,傳入Pad或者Headset都是不可以的。

2.型變

fun main() {
    func(mutableListOf<Phone>(Phone()))	//報錯 這里應該傳入Device類型的集合
}
fun func(list: MutableList<Device>) {
    list.add(Pad())
}
open class Device {
}
class Phone : Device() {
}
class Pad {
}

這里定義了一個方法,方法中的傳參是Device類型的集合,調用的時候傳入的Phone類型的集合,而DevicePhone是繼承關系但是卻無法傳入Phone類型的集合。這是因為在默認情況下MutableList<Device>MutableList<Phone>之間不存在任何繼承關系,他們也無法互相替代,這就是泛型的不變性。

那么什么是型變?型變就是為了解決泛型的不變性問題。

3.型變—逆變

以手機為例,Android是手機類,還有XioMiHuaWei兩個子類,它倆和Android是繼承關系,那么Charger<XiaoMi>、Charger<HuaWei>Charger<Android>之間有什么關系?

class Charger<T> {
    fun charging(device: T) {}
}
open class Android {
    open fun charging() {}
}
class XiaoMi : Android() {
    override fun charging() {
    }
}
class HuaWei() : Android() {
    override fun charging() {
        super.charging()
    }
}

假設,現(xiàn)在手機都沒電了,需要用充電器充電,那么給XiaoMi手機充電就是這樣

fun xiaoMiCharger(charger: Charger<XiaoMi>) {
    val xiaomi = XiaoMi()
    charger.charging(xiaomi)
}

但是還有一個HuaWei手機也要充電,是否可以用一個充電器?就像下面這樣

fun main() {
    val charger = Charger<Android>()
    xiaoMiCharger(charger)				//報錯:類型不匹配
    huaWeiCharger(charger)				//報錯:類型不匹配
}

都是Android手機為什么不能充電?這主要是編譯器不認為XiaoMi和HuaWei是Android手機,也就是說它們三者之間沒有關系,這就是上面講的不可變性, 此時逆變踩著歡快的腳步到來了。

  • 使用處型變
//				   				 修改處
//								   ↓
fun xiaoMiCharger(charger: Charger<in XiaoMi>) {
    val xiaomi = XiaoMi()
    charger.charging(xiaomi)
}
//				   				 修改處
//								   ↓
fun huaWeiCharger(charger: Charger<in HuaWei>) {
    val huaWei = HuaWei()
    charger.charging(huaWei)
}
class Charger<T> {
    fun charging(device: T) {}
}
fun main() {
    val charger = Charger<Android>()	
    xiaoMiCharger(charger)
    huaWeiCharger(charger)
}
  • 聲明處型變
//			修改處
//			  ↓
class Charger<in T> {
    fun charging(device: T) {}
}
fun xiaoMiCharger(charger: Charger<XiaoMi>) {
    val xiaomi = XiaoMi()
    charger.charging(xiaomi)
}
fun huaWeiCharger(charger: Charger<HuaWei>) {
    val huaWei = HuaWei()
    charger.charging(huaWei)
}
fun main() {
    val charger = Charger<Android>()	
    xiaoMiCharger(charger)
    huaWeiCharger(charger)
}

加上in關鍵字之后就報錯就消失了

為什么被叫做逆變?

上面的代碼其實是將父子關系顛倒了,以使用處型變?yōu)槔?,我們把代碼放到一起看看

fun main() {
    val charger = Charger<Android>()	
    xiaoMiCharger(charger)
    huaWeiCharger(charger)
}
//Charger<Android> → Charger<XiaoMi> 成了顛倒關系
fun xiaoMiCharger(charger: Charger<in XiaoMi>) {
    val xiaomi = XiaoMi()
    charger.charging(xiaomi)
}
fun huaWeiCharger(charger: Charger<in HuaWei>) {
    val huaWei = HuaWei()
    charger.charging(huaWei)
}

這種父子顛倒的關系被稱為逆變。

4.型變—協(xié)變

假設我要去商場買一個Android手機,它屬于Phone類

open class Phone {
}
class Android : Phone() {
}
//商場什么都賣
class Shop<T> {
    fun buy(): T {
        TODO("Not yet implemented")
    }
}
//去商場買手機
fun buy(shop: Shop<Phone>) {
    val phone = shop.buy()
}
fun buy(shop: Shop<Phone>) {
    val phone = shop.buy()
}
fun main() {
    val android = Shop<Android>()
    buy(android)				//報錯了,類型不匹配
}

Android是Phone的子類,但是Shop<Android>Shop<Phone>卻沒有關系,這依舊是Kotlin的不可變性,前面講過通過in實現(xiàn)逆變, 但是它的父子關系就被顛倒了,那么這里的目的就是維持正確的父子關系——協(xié)變。

  • 使用處協(xié)變
class Shop<T> {
    fun buy(): T {
        TODO("Not yet implemented")
    }
}
//				   修改處
//					↓
fun buy(shop: Shop<out Phone>) {
    val phone = shop.buy()
}
fun main() {
    val android = Shop<Android>()
    buy(android)				//報錯消失
}
  • 聲明處協(xié)變
//		  修改處
//			↓
class Shop<out T> {
    fun buy(): T {
        TODO("Not yet implemented")
    }
}
fun buy(shop: Shop<Phone>) {
    val phone = shop.buy()
}
fun main() {
    val android = Shop<Android>()
    buy(android)				//報錯消失
}

通過out就實現(xiàn)了協(xié)變, 父子關系也沒有顛倒,關系圖如下

Kotlin的型變的逆變、協(xié)變到這里就講完了,Java中也有型變,但是只有使用處沒有聲明處

KotlinJava
逆變ChargerCharger<? super XiaoMi>
協(xié)變ShopShop<? extends Phone>
//RxJava#ObservableAnySingle
public ObservableAnySingle(ObservableSource<T> source, Predicate<? super T> predicate) {
    this.source = source;
    this.predicate = predicate;
}
//String#join
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
    Objects.requireNonNull(delimiter);
    Objects.requireNonNull(elements);
    StringJoiner joiner = new StringJoiner(delimiter);
    for (CharSequence cs: elements) {
        joiner.add(cs);
    }
    return joiner.toString();
}

逆變和協(xié)變有什么區(qū)別?怎么用?

//聲明處逆變
class Charger<in T> {
    fun charging(device: T) {}
}
//聲明處協(xié)變
//		  修改處
//			↓
class Shop<out T> {
    fun buy(): T {
        TODO("Not yet implemented")
    }
}

對比可以發(fā)現(xiàn)逆變主要用于傳參,協(xié)變主要用于返回值,Kotlin的官方文檔也有這么一句話: ****消費者 in, 生產者 out!

5.泛型邊界

在講協(xié)變的例子時我們要去商場Shop買手機,但是商場什么手機都賣,現(xiàn)在我想買Android手機,怎么保證我買的就是Android手機?加上一個邊界就好了

//				變化在這里,加了一個邊界,類似于var x: Int = 0
//					↓
class Shop<out T: Android> {
    fun buy(): T {
        TODO("Not yet implemented")
        }
}
fun main() {
    val android = Shop<Android>()
        buy(android)
        val ios = Shop<IOS>()		//報錯:類型不匹配
        buy(ios)				
    }
}

6.星投影

星投影就是用【】作為泛型的實參,當我們使用【】作為泛型的實參時也就意味著我們對具體的參數(shù)是什么并不感興趣或者說不知道具體的參數(shù)是什么。

舉例:還是買手機的案例,現(xiàn)在我不挑品牌了,只要能用就好,既然這樣那就隨便找家店鋪好了

//				不指定具體參數(shù)
//					 ↓
fun findShop(): Shop<*> {
    TODO("Not yet implemented")
}
fun main(){
    val shop = findShop()
    val product: Any? = shop.buy()
}

這里的product什么手機都可以,甚至是其他物品都行,這里還定義了一個Any?也說明了可能是空手而歸。

那么我只想買個手機,怎么才能避免買錯成其他物品呢?添加邊界

//只找Phone的店鋪
//					↓ 這是邊界
class Shop<out T: Phone> {
    fun buy(): T {
        TODO("Not yet implemented")
    }
}
fun findShop(): Shop<*> {
    TODO("Not yet implemented")
}
fun main() {
    val shop = findShop()
    //只要返回值是Phone的商品
    val product: Phone = shop.buy()
}

添加邊界后就可以達到我只想買個手機的要求了。

泛型這一塊比較抽象,一定要多看幾遍,思考在項目中這個東西的應用場景在哪里。

以上就是Kotlin 泛型邊界型變及星投影使用詳解的詳細內容,更多關于Kotlin 泛型型變星投影的資料請關注腳本之家其它相關文章!

相關文章

  • Android PicSelector圖片選擇器小功能

    Android PicSelector圖片選擇器小功能

    這篇文章主要為大家詳細介紹了Android PicSelector圖片選擇器小功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Android開發(fā)No Focused Window ANR產生原理解析

    Android開發(fā)No Focused Window ANR產生原理解析

    這篇文章主要為大家介紹了Android開發(fā)No Focused Window ANR產生原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Flutter WillPopScope攔截返回事件原理示例詳解

    Flutter WillPopScope攔截返回事件原理示例詳解

    這篇文章主要為大家介紹了Flutter WillPopScope攔截返回事件原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • Android Studio中debug功能詳解

    Android Studio中debug功能詳解

    這篇文章主要為大家詳細介紹了Android Studio中debug功能的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • flutter實現(xiàn)更新彈窗內容例子(親測有效)

    flutter實現(xiàn)更新彈窗內容例子(親測有效)

    Flutter是一款移動應用程序SDK,包含框架、widget和工具,這篇文章給大家介紹flutter實現(xiàn)更新彈窗內容例子,親測可以使用,需要的朋友參考下吧
    2021-04-04
  • Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實現(xiàn))

    Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實現(xiàn))

    這篇文章主要介紹了Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實現(xiàn))的相關資料,需要的朋友可以參考下
    2015-10-10
  • Kotlin基礎學習之位運算

    Kotlin基礎學習之位運算

    一提起位運算,人們往往想到它的高效性,無論是嵌入式編程還是優(yōu)化系統(tǒng)的核心代碼,適當?shù)倪\用位運算總是一種迷人的手段,下面這篇文章主要給大家介紹了關于Kotlin基礎學習之位運算的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2017-11-11
  • AndroidX下使用Activity和Fragment的變化詳解

    AndroidX下使用Activity和Fragment的變化詳解

    這篇文章主要介紹了AndroidX下使用Activity和Fragment的變化詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • Android 安全加密:數(shù)字簽名和數(shù)字證書詳解

    Android 安全加密:數(shù)字簽名和數(shù)字證書詳解

    本文主要介紹Android 安全加密數(shù)字簽名和數(shù)字證書的資料,這里整理詳細的資料及數(shù)字簽名和數(shù)字證書應用詳解,有需要的小伙伴可以參考下
    2016-09-09
  • 故事講解Activity生命周期(貓的一生)

    故事講解Activity生命周期(貓的一生)

    關于Android中Activity的生命周期,網上大多數(shù)文章基本都是直接貼圖、翻譯API,比較籠統(tǒng)含糊不清。本文主要用故事講解Activity生命周期。下面跟著小編一起來看下吧
    2017-03-03

最新評論