当前位置: 首页 > news >正文

ink域名网站百度惠生活商家入驻

ink域名网站,百度惠生活商家入驻,日本b2b平台有哪些,企业官网运营Kotlin的泛型与Java十分类似&#xff0c;也是使用这种的语法结构&#xff1a; class Fruit<T> {fun eat(f : T): Unit {println("eat...")}fun <T> buy(p : T): T {return p} }泛型限制 和Java一样&#xff0c;Kotlin也允许泛型是某个类的子类 fun &l…

Kotlin的泛型与Java十分类似,也是使用这种的语法结构:

class Fruit<T> {fun eat(f : T): Unit {println("eat...")}fun <T> buy(p : T): T {return p}
}
泛型限制

和Java一样,Kotlin也允许泛型是某个类的子类

fun <T : Number> other(p : T): T {return p
}
泛型实化

Java的泛型是使用泛型擦除机制来实现的,所以只存在于编译时期,所以所有基于JVM的语言他们的泛型都是通过类型擦除机制实现的,Kotlin也不例外,这种机制使得我们不可能使用a is T或者T::class.java这些的写法了,因为T在运行时类型已经被擦除了。

然而Kotlin剔红了一个内联函数的概念,内联函数在编译时会自动被替换它被调用的地方,这样也就不存在什么泛型擦除的问题了,因为代码在编译的时候会直接使用实际的类型来替代内联函数中的泛型声明。

这意味着Kotlin是可以将内联函数中的泛型进行实化的,那怎样实现呢?首先函数必须是内联函数且声明泛型的地方需要使用reified进行修饰,举个例子:

fun main() {var r = getGenericType<String>()var m = getGenericType<Int>()println("r is $r")println("m is $m")
}inline fun <reified T> getGenericType() = T::class.java

输出结果:r is class java.lang.String
m is class java.lang.Integer

而Java是不可能实现上述功能的,因为在编译后,泛型这个约束对于JVM已经不存在了。

泛型协变

泛型的协变与逆变功能就基本用不到,但是还是讲一下,避免在看别人代码的时候看不懂是什么意思。

首先我们需要讲一个概念,在泛型类或者泛型方法中,参数列表是接收数据的地方,因此可以称它的位置是in位置,而返回类型的地方是输出数据的地方,因此可以称它为out。

接下来我们定义三个类:

open class Person(val name: String, val age: Int)
class Student(name: String, age: Int): Person(name, age)
class Teacher(name: String, age: Int): Person(name, age)

接下来问你一个问题,假设在Java中一个方法接收Person类型的参数,而你传递一个Student可以吗,当然可以吧。

但是,如果方法接收的参数是一个List你传递一个List这样可以吗,这样是不行的,不行你去试一下,不行的原因主要是Java为了防止类型转换的安全隐患,我们举个例子,假设有个Data的泛型类:

class Data<T> {var value: T? = nullfun set(v: T?) {this.value = v}fun get(): T? {return this.value}
}

fun main() {var s = Student("XuanRan", 18)var d = Data<Student>()d.set(s)handle(d) // 此行报错println(d.get())
}fun handle(data: Data<Person>) {data.set(Teacher("Tom", 17))
}

我们假设报错的那一行能够正常编译通过,按照程序逻辑,如果我们上面提到的问题允许的话,那么经过handle处理后的Data将不再是原来的Student,所以为了杜绝这种情况,Java直接禁用掉了这种方式,换句话讲,即使Student是Person的子类,但是Data并不是Data的子类。

不过,我们一起回顾一下代码,出现这种问题的主要原因是因为我们在handle方法内部,通过data给设置了Teacher对象,如果Data在泛型T上是只读的话,那肯定没有类型转换异常了,所以我们只要确保泛型类在其泛型数据上是只读的话那么它是没有类型转换安全隐患的,换句话说我们在Data类里面,只要保留get方法,不要暴露set方法供外部调用,只在构造方法中进行参数设置即可,要实现这一点,只要让这个泛型类的所有方法(构造除外)都不能去接收T类型的参数,换句话说,T只能出现在out位置,而不是in位置,如下代码所示:

class Data<out T>(val value: T) {fun get(): T? {return this.value}
}

我们在T之前使用out进行修饰,此时类中所有含参数T的方法都会报错,并且我们在这个类中添加常量value,此时,我们再或过头看之前的代码,会发现handle调用不报错了,而handle方法的实现中,调用Data内部的set方法报错,这很正常,因为我们删掉了set。

fun main() {var s = Student("XuanRan", 18)var d = Data(s)handle(d)println(d.get())
}fun handle(data: Data<Person>) {// todo
}

这样我们就实现了泛型的协变。

除此之外,Kotlin已经给很多内置的API加上了协变的声明,其中就包括了各种集合类与接口,还记得我们之前提到的使用listOf只能创建只读的集合吗,我们现在就来看一下List的精简源码

public interface List<out E> : Collection<E> {override val size: Intoverride fun isEmpty(): Booleanoverride fun contains(element: @UnsafeVariance E): Booleanoverride fun iterator(): Iterator<E>public operator fun get(index: Int): E
}

List在泛型E的前面加上了out关键字,说明List在泛型E上是协变的。不过这里还有一点需要说 明,原则上在声明了协变之后,泛型E就只能出现在out位置上,可是你会发现,在 contains()方法中,泛型E仍然出现在了in位置上。

这么写本身是不合法的,因为在in位置上出现了泛型E就意味着会有类型转换的安全隐患。但是 contains()方法的目的非常明确,它只是为了判断当前集合中是否包含参数中传入的这个元 素,而并不会修改当前集合中的内容,因此这种操作实质上又是安全的。那么为了让编译器能够理解我们的这种操作是安全的,这里在泛型E的前面又加上了一个@UnsafeVariance注解, 这样编译器就会允许泛型E出现在in位置上了。

泛型逆变

我们定义一个Transformer对象,并接收一个Person的泛型,此外要求接口实现类必须重写自己的trans方法,然后我们在main中实现了这个接口,这个接口trans的返回值将会返回Person的名字和姓名,并且定义了一个方法handle,用于输出一个学生的姓名,但是handle在调用的时候会报错语法错误,因为方法要求接收的是Transformer的泛型,而传递过来的却是Transformer的泛型,换句话说,Transformer并不是Transformer的子类型。

interface Transformer<T> {fun trans(t: T): String
}fun main() {// 实现一个Transformer接口val t = object : Transformer<Person> {// 定义我们自己的trans方法override fun trans(t: Person): String {// 该方法会返回Person类的名称和年龄return "${t.name} ${t.age}"}}handle(t) // 此处语法错误
}/*** 该函数接收一个Transformer的对象,要求泛型为Student*/
fun handle(s: Transformer<Student>) {var student = Student("XuanRan", 12)println(s.trans(student))
}

要解决这个问题,我们就可以使用泛型的逆变,也就是in关键字,修改Transformer代码,如下所示:

interface Transformer<in T> {fun trans(t: T): String
}

然后代码就能正常编译输出了,这就是泛型的逆变。

http://www.dt0577.cn/news/31116.html

相关文章:

  • 网站建设 万户建站关键词搜索量查询工具
  • 乡政府网站建设实施方案南昌seo代理商
  • 建设网站 买了域名还要什么免费软文发布平台
  • 怎么用css做网站分片企业推广网络营销外包服务
  • 哪个网站专注做微信模板360收录提交
  • 新建的网站百度搜索不到百度指数网址是多少
  • 给别人做彩票网站违法吗百度搜索引擎营销案例
  • html简单网页代码课程表seo成创网络
  • 哪个网站做设计兼职不用压金互联网营销策划
  • 怎样用编程语言做网站北京十大最靠谱it培训机构
  • 苏州市住建局官方网站百度ai搜索引擎
  • 自己做网站要买服务器吗淘宝关键词指数查询
  • 宠物网站建设策划方案百度云引擎搜索
  • 南京网站设计制作公司排名榜四年级写一小段新闻
  • 襄阳住房和城乡建设网站宁波seo排名优化培训
  • 在线设计工具的网站怎么做百度关键词优化软件如何
  • 网站开发企业需要什么资质网站名查询网址
  • 山东网站建设国际域名注册网站
  • 个人做网站法律风险乐陵seo优化
  • 网站建设与管理基础及实训(php版)什么是网络营销工具
  • dedecms5.7 财经网站网络营销的概念及内容
  • 手机微信官方网站关键词seo服务
  • 有什么做服装的网站关键词点击排名系统
  • 什么网站可以做ui兼职简述seo的基本步骤
  • 网站专用app软文营销广告案例
  • 网站开发行情seo推广视频隐迅推专业
  • 网站后台图片滚动效果怎么做企业网站设计制作
  • 网站可以免费建设吗国内网络推广渠道
  • 做一个交易网站多少钱想开广告公司怎么起步
  • app开发与网站建设难度如何优化关键词的方法