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

济南精品建站外包公司价格江门网红打卡点

济南精品建站外包公司价格,江门网红打卡点,项目建设我先行凝心聚力促发展,济南网站制作的公司以下内容摘自郭霖《第一行代码》第三版 泛型的协变 一个泛型类或者泛型接口中的方法,它的参数列表是接收数据的地方,因此可以称它为in位置,而它的返回值是输出数据的地方,因此可以称它为out位置。 先定义三个类: op…

以下内容摘自郭霖《第一行代码》第三版

泛型的协变

一个泛型类或者泛型接口中的方法,它的参数列表是接收数据的地方,因此可以称它为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)

定义一个SimpleData类

class SimpleData<T> {private var data: T? = nullfun set(t: T?) {data = t}fun get(): T? {return data}
}

那么以下代码就会存在编译问题:

fun main() {val student = Student("Tom", 19)val data = SimpleData<Student>()data.set(student)handleSimpleData(data) 							// 实际上这行代码会报错val studentData = data.get()
}
fun handleSimpleData(data: SimpleData<Person>) {val teacher = Teacher("Jack", 35)data.set(teacher)
}

即使Student是Person的子类,SimpleData<Student>并不是SimpleData<Person>的子类。

问题发生的主要原因是我们在handleSimpleData()方法中向SimpleData<Person>里设置了一个Teacher的实例。如果SimpleData在泛型T上是只读的话,肯定就没有类型转换的安全隐患了。

泛型协变的定义:假如定义了一个MyClass<T>的泛型类,其中A是B的子类型,同时MyClass<A>又是MyClass<B>的子类型,那么我们就可以称MyClass在T这个泛型上是协变的。

要实现一个泛型类在其泛型类型的数据上是只读,则需要让MyClass<T>类中的所有方法都不能接收T类型的参数。换句话说,T只能出现在out位置上,而不能出现在in位置上。

修改SimpleData类的代码:

class SimpleData<out T>(val data: T?) {fun get(): T? {return data}
}

在泛型T的声明前面加上了一个out关键字。这就意味着现在T只能出现在out位置上,而不能出现在in位置上,同时也意味着SimpleData在泛型T上是协变的。

由于泛型T不能出现在in位置上,因此我们也就不能使用set()方法为data参数赋值了,所以这里改成了使用构造函数的方式来赋值。由于这里我们使用了val关键字,所以构造函数中的泛型T仍然是只读的,因此这样写是合法且安全的。另外,即使我们使用了var关键字,但只要给它加上private修饰符,保证这个泛型T对于外部而言是不可修改的,那么就都是合法的写法。

fun main() {val student = Student("Tom", 19)val data = SimpleData<Student>(student)handleMyData(data)val studentData = data.get()
}
fun handleMyData(data: SimpleData<Person>) {val personData = data.get()
}

由于SimpleData类已经进行了协变声明,那么SimpleData<Student>自然就是SimpleData<Person>的子类了,所以这里可以安全地向handleMyData()方法中传递参数。

然后在handleMyData()方法中去获取SimpleData封装的数据,虽然这里泛型声明的是Person类型,实际获得的会是一个Student的实例,但由于Person是Student的父类,向上转型是完全安全的,所以这段代码没有任何问题。

Kotlin已经默认给许多内置的API加上了协变声明,其中就包括了各种集合的类与接口。

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
}

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

泛型的逆变

假如定义了一个MyClass<T>的泛型类,其中A是B的子类型,同时MyClass<B>又是MyClass<A>的子类型,那么我们就可以称MyClass在T这个泛型上是逆变的。

逆变与协变的区别:

在这里插入图片描述

先定义一个Transformer接口,用于执行一些转换操作:

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

现在尝试对Transformer接口进行实现:

fun main() {val trans = object : Transformer<Person> {override fun transform(t: Person): String {return "${t.name} ${t.age}"}}handleTransformer(trans) // 这行代码会报错
}
fun handleTransformer(trans: Transformer<Student>) {val student = Student("Tom", 19)val result = trans.transform(student)
}

这段代码从安全的角度来分析是没有任何问题的,因为Student是Person的子类,使用Transformer<Person>的匿名类实现将Student对象转换成一个字符串也是绝对安全的,并不存在类型转换的安全隐患。但是实际上,在调用handleTransformer()方法的时候却会提示语法错误,原因也很简单,Transformer<Person>并不是Transformer<Student>的子类型。

那么这个时候逆变就可以派上用场了,它就是专门用于处理这种情况的。修改Transformer接口中的代码:

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

这里我们在泛型T的声明前面加上了一个in关键字。这就意味着现在T只能出现在in位置上,而不能出现在out位置上,同时也意味着Transformer在泛型T上是逆变的。

Kotlin在提供协变和逆变功能时,就已经把各种潜在的类型转换安全隐患全部考虑进去了。只要严格按照其语法规则,让泛型在协变时只出现在out位置上,逆变时只出现在in位置上,就不会存在类型转换异常的情况。虽然@UnsafeVariance注解可以打破这一语法规则,但同时也会带来额外的风险。

逆变比较典型的例子就是Comparable的使用。Comparable是一个用于比较两个对象大小的接口,其源码定义如下:

interface Comparable<in T> {operator fun compareTo(other: T): Int
}
http://www.yayakq.cn/news/665657/

相关文章:

  • 西安网站开发技术xp花生壳做网站
  • 国外教做蛋糕的网站2017网站建设费用
  • 百度移动端关键词优化福州短视频seo推荐
  • 电子商务实网站的建设自定义页面wordpress
  • 做街舞网站的素材天眼查询个人信息免费
  • 乌克兰网站后缀个人可以做购物网站吗
  • 赣州有没有做网站的久久项目咨询有限公司
  • 网站需要写哪些内容中国服务器龙头企业
  • 网站改版不换域名建设部网站一级开发资质
  • 天津北京网站建设公司怎么做类似知乎的网站
  • 寻找网站建设甘肃省建设厅门户网站
  • 澧县住房和城乡建设局网站食品类网站模板
  • 网页制作与网站建设技术大全 pdfwordpress路由与模板调用
  • 用dw做网站怎么换行下载素材的网站
  • 免费网站能到百度首页吗最新公告哈尔滨
  • 广州市天河区门户网站文档下载免费网站
  • 微信公众号登录wordpress网站吗个人怎么做网站页面
  • 网站注册系统用什么做企业年金查询个人账户查询
  • 揭阳东莞网站建设大连工业大学图书馆
  • 网站广告看不到html代码入门基础
  • 如何有效的进行网站策划网站后台ftp账户
  • 长春建站优化加徽信xiala5万网网站备案产品验证未找到该域名授权信息
  • 写作网站哪个比较赚钱什么网站可以做长图
  • 中小企业网络架构开鲁网站seo
  • t型布局网站wordpress怎么做激活验证
  • 国内网站用django做的网站建设与维护 课件
  • 怎么做一网站网页设计适合什么岗位
  • 注册网站需要注意什么定远建设局官方网站
  • zencart 网站安装wordpress被镜像
  • 网站设计的一般步骤是什么?卡盟网站怎么做图片素材