Kotlin-泛型

关于什么是泛型, 看另一篇文章 https://www.jianshu.com/p/7eac2f36036e

参数化函数(泛型函数)

  1. 在函数名前边加上<T>实现参数化函数
  2. 函数的参数至少有一个是T类型, 否则编译器无法推断出T的类型
fun <T> foo (input: T): T {
    return input
}

函数的返回值可以是任何类型, 但不能用运行时的类型

fun <T> foo (input: T): String {
    return input // 即使我们在运行时传入了一个字符串也不行, input的类型是T, 与运行时的类型无关
}

参数化类型

参数化类型主要用在各种容器类型上, 这种类型内部可以包含其他类型的数据, 比如list, map

class Sequence<T> // 定义一个参数化类型
val seq = Sequence<Int>() //传入Int类型

上界类型约束

将类型限制为某个类的子类, 如果省略, 将会是Any

fun <T: Number> convert(a: T, b: T)  // 将T的类型限制为Number的子类
fun <T> convert(a: T, b: T)  // T的类型限制为Any

Invariance (不变)

类型不变指泛型类型默认是没有继承上的关系的, M<Int>并不是M<Number>的一个子类型.
这样设计的原因, 参考这个例子:

fun foo(m: M<Number>): Unit {
  m.add(123L)
}

假设有一个M<Int>型的集合x, 执行foo(x)后, 如果类型有继承关系, 由于IntLong都是Number的子类型, 就会往x里添加一个Long型元素, 这违背了类型安全的原则.

Covariance (协变)

协变是改变类型之间的关系, 使他们有继承性.

fun foo(m: M<Number>): Unit {
  m.functionFromNumber()
}

假设foo函数会调用一个Number类的方法, 这样我们就不用管传入的是m<int>, 还是m<Long>都无所谓(因为函数定义在父类上), 此时就需要协变`来让类型有继承关系.

class M<out T>

使用outT定义为协变类型之后, 不能用T作为函数的输入参数(形参), 可以做返回值. 像m.add(T)是非法的.

逆变 Contravariance

逆变是反转两个类的继承关系, 比如逆变后, M<Int> 是 M<Number> 的父类.

这个需求是这样的

Event<String>(stringHandler)
Event<Number>(numberHandler)

我们有两种Event, 分别用对应类型的Handler处理, 假设我们想用一个通用的handler比如: commonHandler<Any>`来处理.

Event<String>(commonHandler)
Event<Number>(commonHandler)

答案是不行, 因为AnyString的父类, 而Event只能使用String或它的子类. 通过逆变, Any就变成了String的子类.

class Event<in T>(val handler: Handler<T>)
class Handler<in T>
...

逆变后, 类型只能作为输入参数(形参), 不能作为返回值类型.

type projection

类型的variance有两种, use site(java) 和 declaration site(Kotlin), type projection 允许我们使用use site variance, 它的思想是, 如果我们无法在类定义(比如使用别人的类)时使用covariance或contravriance(即declaration site), 我们可以在定义函数时, 规定函数将如何使用类型.

fun foo(m: M<out Number>): Unit {
  m.functionFromNumber()
}

同理, contravariant

class Event<in T>(val handler: Handler<in T>) // 构造函数的in T

type projection定义了我们如何使用函数, 而不需修改原类型声明

Type reification

由于JVM在编译时会把所有泛型类型(不包括基础数据类型)信息擦除, kotlin同样如此, 使用Type reification, kotlin可以为inline 函数保留泛型类型信息.

inline fun <reified T>printT(any: Any): Unit {
    if (any is T)
    println("I am a tee: $any")
}

这个函数可以在运行时获取到T的传入类型. 类型具体化只能用于inline函数, 因为inline函数的执行是把函数体内容直接拷贝到调用处, 此时通过传递的参数可以知道T的类型. 其他函数无法使用类型具体化

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容

  • 泛型 泛型(Generic Type)简介 通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么...
    Tenderness4阅读 1,416评论 4 2
  • 本博文主要讲解一些Kotlin泛型的问题,中间会对比穿插Java泛型。 1. 泛型类型参数 1.1 形式 我们使用...
    24K男阅读 18,445评论 4 11
  • 转载文章,出处: https://blog.kotliner.cn/2017/06/26/kotlin-gener...
    _10_01_阅读 691评论 0 0
  • 与Java一样,Kotlin也支持泛型,为类型安全提供保证,消除类型强转的烦恼 创建类的实例时我们需要指定类型参数...
    郎官人阅读 1,240评论 0 0
  • 文~小丸子 2017-7-16 周日 纠结了一会,还是爬起来坐到电脑前面了。 近期,其实很多次有些想法,想写下来。...
    云淡风轻小丸子阅读 229评论 0 0