IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin 泛型 | 02. 高阶 - 型变 -> 正文阅读

[移动开发]Kotlin 泛型 | 02. 高阶 - 型变

三、泛型型变:协变、逆变与不变

3.1 协变

3.1.1 基本定义

????????如果在定义的泛型类、接口和泛型方法的泛型参数前面加上 out 关键词,说明这个泛型类、接口和泛型方法是协变

????????也就是说,A 是 B 的子类,那么 List<A> 也是?List<B> 的子类。

class Demo {
    interface Producer<out T> { // 在泛型类型形参前面指定 out 修饰符
        val something: T
        fun produce(): T
    }
}

????????那么,协变如何解决类型不安全的问题?——只能读,不能写;只能作为方法返回值或修饰只读权限的属性,不能作为方法参数类型或可变权限的属性。

3.1.2 关键内容

  • out;
  • 生产者;
  • 只能读,不能写;
  • 对应 Java 中?Collection<? extends Object>
  • 只能作为方法返回值或修饰只读权限的属性,不能作为方法参数类型;

????????注:Kotlin 中的 List 并不是 Java 中的 List,因为 Kotlin 中的 List 是个只读的 List,不具备修改集合中元素的操作方法。Java 中的 List 实际上相当于 Kotlin 中的 MutableList,它具有各种读和写的操作方法。

3.2 逆变

3.2.1 基本定义

????????如果在定义的泛型类、接口和泛型方法的泛型参数前面加上 in 关键词,说明这个泛型类、接口和泛型方法是逆变

????????也就是说,A 是 B 的子类,那么 List<B> 反过来是?List<A> 的子类。

class Demo {
    interface Consumer<in T> { // 在泛型类型形参前面指定 in 修饰符
        fun consume(value: T)
    }
}

????????那么,逆变如何解决类型不安全的问题?——只能写,不能读;只能作为方法的形参类型或修饰可变权限的属性。

3.2.2 关键内容

  • in;
  • 消费者;
  • 只能写,不能读;
  • 对应 Java 中 List<? super String>
  • 只能作为方法的形参类型或修饰可变权限的属性;

3.2.3 加深理解的Demo参考如下:

正常情况下:

class Demo {
    private val doubleList = mutableListOf(2.0, 3.0)
    private val intList = mutableListOf(2, 3)

    private val doubleComparable = Comparator<Double> { d1, d2 -> // 一个 Double 类型比较器
        d1.compareTo(d2)
    }
   
    private val intComparable = Comparator<Int> { i1, i2 -> // 一个 Int 类型比较器
        i1.compareTo(i2)
    }

    fun test() {
        doubleList.sortWith(doubleComparable)
        intList.sortWith(intComparable)
    }
}

使用逆变后:

class Demo {
    private val doubleList = mutableListOf(2.0, 3.0)
    private val intList = mutableListOf(2, 3)

    private val numberComparable = Comparator<Number> { n1, n2 -> // 一个 Number 父类型比较器
        n1.toDouble().compareTo(n2.toDouble())
    }

    fun test() {
        doubleList.sortWith(numberComparable)
        intList.sortWith(numberComparable)
    }
}

3.3 不变

????????除去协变和逆变就是不变了,它就是我们常用的普通泛型,它既没有 in 关键字修饰,也没有 out 关键字修饰。

class Demo {
    interface MutableList<E> { // 没有 in 和 out 修饰
        fun add(element: E) // E可以作为函数形参类型处于逆变点,输入消费 E
        fun subList(fromIndex: Int, toIndex: Int): MutableList<E> // E又可以作为函数返回值类型处于协变点,生产输出 E
    }
}

3.4 生产者、消费者的概念

????????Joshua Bloch 称那些你只能从中读取的对象为生产者,并称那些你只能写入的对象为消费者。他建议:“为了灵活性最大化,在表示生产者或消费者的输入参数上使用通配符类型”,并提出了以下助记符:

????????PECS 代表生产者-Extends、消费者-Super(Producer-Extends, Consumer-Super)。

注意:如果你使用一个生产者对象,如?List<? extends Foo>,在该对象上不允许调用?add()?或?set()。但这并不意味着该对象是不可变的:例如,没有什么阻止你调用?clear()从列表中删除所有元素,因为?clear()?根本无需任何参数。通配符(或其他类型的型变)保证的唯一的事情是类型安全。不可变性完全是另一回事。

3.5 Kotlin与Java的型变比较

不变协变逆变
kotlin实现方式:<T>,可读可写实现方式:<out T>,只能读不能写,生产者实现方式:<in T>,只能写不能读,消费者
Java实现方式:<T>,可读可写实现方式:<? extends T>,只能读不能写,生产者实现方式:<? super T>,只能写不能读,消费者

自创顺口溜:

泛型本是不变,Kotlin让它型变;

协变加逆变,就是没有裂变。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:51:16  更:2021-07-30 12:53:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 10:37:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码