在上一次https://www.cnblogs.com/webor2006/p/11234941.html中学习了数据类[data class]相关的知识,这次会学习关于泛型相关的东东,其中有关于泛型我经常不太理解的关于<? extends T>和<? super T>的使用方式,所以好好学习,天天向上。

密封类(sealed class):

关于这个类,我们在上一次学习中其实是提到过这个关键字,回忆一下:

所谓密封,就是将东东给包装起来,然后我们要使用只能使用包装好里面受限的东东,其实跟Java的枚举很类似,但又跟枚举不太一样,其实它是枚举的一个扩展,枚举我们知道在定义时其实例就已经规定好了,关于密封类跟java枚举的区别等学会了用密封类之后就能体会到了 ,而密封类其实描述的是类的一种层次,也就是父类和子类的一种关系,而密封类的子类可以有多个,说了这么说那也不知道在说啥,直接来撸码来看下密封类是个什么东东,在撸码之前先明白个规则:

1、在Kotlin中如果一个密封类有若干个子类,那么密封类和子类必须定义在同一个文件当中,其中在Kotlin1.1版本之前对于它的规定更加的严格,当时是要求密封类的子类必须要定义在密封类里面,而在Kotlin1.1版本以后就打开了这个限定了。

2、在Kotlin中,密封类是一个抽象类,不能实例化。

好,下面来定义一个密封类:

因为它是抽象的,所以可以定义几个子类,如下:

这样写貌似有点想写多态的感觉,肯定还得定义一个计算方法呗,下面定义一下:

下面来调用一下:

貌似跟枚举使用没啥太大的区别,好,接下来再来定义一个子类区别就可以显现了,如下:

看懂了密封类的作用木有,也就是它就是描述一种类的层次关系,目前我们密封类定义了三个子类,而when表达式的条件也必须有三种可能,而Java中的枚举是没有这一层关系的,下面来修改一下程序:

也就是用了密封类之后,我们在用when表达式时就可以不用else分支了,假如我们强行加上else则IDE会报冗余提示:

可以看一下我们的密封类和子类是定义在了一个文件当中,符合之前说的规定:

而如果说我们再定一个类,来继承密封类的子类,那就没有这个“必须定义到一个文件里”的限制了。

泛型(generics):

关于泛型是啥,用一句描述是:表示变量类型的参数化,其语法跟Java类似,如下:

上面泛型是一个完整的使用方式,其实可以精简一下,利用Kotlin的推断机制,如下:

协变[covariant]与逆变[controvariant]原理剖析:

关于泛型的使用其实很简单,但是!!如文章开头所说,一直理解不了在Java框架中很多使用泛型都会用<? extends T>和<? super T>,像Rxjava中:

所以这次抛开语言层面来对泛型这块的东东彻底把它搞清楚,也就是关于泛型的协变与逆变的概念,下面先从Java的具体泛型的示例中来开始一点点理解它:

一切很自然,但是!!!我们不能这样做:

这是为啥呢?假设这个等式成立的话,那可以这样写:

由于list2指向了list,那么我可以以list的角度来取数据,那么就会有:

为了解决这样的问题,Java提供了通配符,如下:

下面再以集合为例对其进行说明:

集合接口中定义了一个addAll()方法,可以添加现已经存在的集合, 下面定义一个添加方法:

很显然此添加方法在实际需求中是很常见的,这里就可以瞅一下JDK自带的Collection.addAll()方法的定义:

所以咱们校仿一下:

这样的话,我们就可以很安全的当E类型从集合中去读取,也就是会当Object的类型来读取,所以Collection<String>是Collection<? extends Object>的子类型,这种情况就叫做协变,它只会从集合中当成Object来读取元素,协变是针对读取的;而相反如果这样写的话则是逆变,逆变是针对写入的,如下:

也就是往集合中写元素时必须是String以上的类型,另外需要明白:我们如果只从中读取数据,而不往里面写入内容,那么这样的对象叫做生产者,也就是协变,此时使用 ? extends E;如果只向里面写入数据,而不从中读取数据,那么这样的对象叫做消费者,也就是逆变,使用? super E。貌似看标的这句话跟预想的理解有点出入,反正先记住这个结论。

下面来看一下在Kotlin中如何来解决协变和逆变的问题,如下:

一切如预期,接下来要改动程序了:

此时可以看到我们定义的泛型,在整个类中只有读取,没有写入,如下:

这其实是协变,这时如果在Java中就可以声明为? extents T,但是在Koltin中用它来表示协变:

这样就比Java直观,表示该泛型是要被读的,那如果给T增加一个写方法呢?

提示如下:

所以可见对于协变只能用到读,接下来定义一个逆变:

而由于Int的父类是Number,如下:

所以咱们改一下程序:

此时对应的也得改一下调用:

此时报错了,这里就可以加上in逆变关键字,如下:

Kotlin泛型与协变及逆变原理剖析的更多相关文章

  1. C#4.0泛型的协变,逆变深入剖析

    C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...

  2. C#-弄懂泛型和协变、逆变

    脑图概览 泛型声明和使用 协变和逆变 <C#权威指南>上在委托篇中这样定义: 协变:委托方法的返回值类型直接或者间接地继承自委托前面的返回值类型; 逆变:委托签名中的参数类型继承自委托方法 ...

  3. .NET 4.0中的泛型的协变和逆变

    转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...

  4. Java用通配符 获得泛型的协变和逆变

    Java对应泛型的协变和逆变

  5. 转载.NET 4.0中的泛型的协变和逆变

    先做点准备工作,定义两个类:Animal类和其子类Dog类,一个泛型接口IMyInterface<T>, 他们的定义如下:   public class Animal { } public ...

  6. Java泛型的协变与逆变

    泛型擦除 Java的泛型本质上不是真正的泛型,而是利用了类型擦除(type erasure),比如下面的代码就会出现错误: 报的错误是:both methods  have same erasure ...

  7. C# 泛型的协变和逆变

    1. 可变性的类型:协变性和逆变性 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用.如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量.协变和逆变是两个相互对立的概念: 如 ...

  8. C# 泛型的协变和逆变 (转载)

    1. 可变性的类型:协变性和逆变性 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用.如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量. 协变和逆变是两个相互对立的概念: ...

  9. c#-泛型、协变、逆变

    泛型简单介绍: 可以使用泛型声明的元素:类.接口.方法.委托 泛型之前:泛型之前使用object封装不同类型的参数,缺点:性能差.运行时判断类型(不安全)...泛型是在编译期间转为实际类型副本,所以性 ...

随机推荐

  1. 在CentOS 7中 使用 Nginx 反代 .Net Core

    很久没弄 .Net Core 了,然后忽然发现Windows自带的 Hyper-V 虚拟机貌似挺好用的 .Net Core 之前都是用 Jexus 来做服务器,忽然想用下Nginx来试试 1.在 Ce ...

  2. NGINX安全配置和限制访问

    说起网络攻击,可能很多人只知道大名鼎鼎的DDOS攻击,这种攻击廉价且效果出众,直接通过第四层网络协议用他的带宽把你的带宽顶掉,造成网路阻塞,防不胜防,就连腾讯这种大鳄公司也被大流量DDOS搞过焦头烂额 ...

  3. 使用WinFrom + CefSharp 开发客户端程序

    今天使用CefSharp,加上本地资源文件嵌入了HTML.CSS.JS文件,做为Winform的UI:效果不错,漂亮可控,简简单单,半天时间搞定从开发到上线: 下面记录下相关的备忘: (窗口的效果) ...

  4. LeetCode 223. 矩形面积(Rectangle Area)

    223. 矩形面积 223. Rectangle Area 题目描述 在二维平面上计算出两个由直线构成的矩形重叠后形成的总面积. 每个矩形由其左下顶点和右上顶点坐标表示,如图所示. LeetCode2 ...

  5. [转帖]GNU, Free Software and Open Source 自由软件与开源软件

    GNU, Free Software and Open Source 自由软件与开源软件 https://blog.csdn.net/icycolawater/article/details/7792 ...

  6. Prometheus入门到放弃(7)之redis_exporter部署

    redis监控,prometheus需要使用redis_exporter客户端. 这里我们采用docker方式部署,既可以部署在redis所在服务器,也可以部署在其他机器: docker镜像地址:ht ...

  7. KAFA优点和缺点

    我们上一期的Kafka教程中,我们讨论了Kafka的Books.今天,我们将讨论卡夫卡的优势和劣势.因为,在使用之前了解任何技术的局限性非常重要,在优点的情况下也是如此.所以,让我们详细讨论卡夫卡优势 ...

  8. Tomcat是一个Servlet容器?

    "Tomcat是一个Servlet容器",这句话对于2019年的程序员应该是耳熟能详的. 单纯的思考一下这句话,我们可以抽象出来这么一段代码: class Tomcat { Lis ...

  9. Java开发笔记(一百二十)AWT文本标签

    前面介绍了AWT窗口及其面板的简单用法,其中展示出来的控件只有按钮一种,还有很多好用好玩的控件有待介绍.首先是文本标签Label,该控件用于显示一段平铺文本,它不花哨也不跳动,完全就是素面朝天的文本字 ...

  10. c++快速排序原理及优化

    快速排序 快速排序的时间复杂度为O(logn) 注意:快速排序主要是标志数的选取,如果所选的数恰好为最小或者最大,则是最糟糕的情况,即一轮下来数据没有发生变化! 如何选取中间的标志数成为了算法的关键. ...