泛型

作者: 夜远曦白 | 来源:发表于2020-05-14 14:11 被阅读0次

泛型的定义

  • 泛型即“参数化类型”,就是将具体的类型变成参数化类型,在声明一个泛型时,传递的是一个类型形参,在调用时传递的是一个类型实参

  • 泛型是在类型名之后、主构造函数之前用尖括号“<>”括起来的大写字母类型参数

泛型的分类

  • 使用泛型标记的类,被称为泛型类。
  • 当泛型类用于实例化时,需要传递具体的类型实参。
  • 当泛型类被用于继承时,需要为泛型形参提供一个具体类型或者另一个类型的形参
自定义泛型类格式
  • 使用泛型标记的接口,被称为泛型接口

  • 泛型接口被实现时能够确定泛型接口对应的实参,直接传递实参即可

image.png
  • 泛型接口被实现时不能够确定泛型接口对应的实参,则需要使用当前类或者接口的泛型形参
image.png
  • 使用泛型标记的方法,被称为泛型方法
自定义泛型方法格式

泛型的约束、子类与子类型

  • 泛型约束是对类或者方法中的类型变量进行约束

  • 泛型约束<T:类或接口>与Java中的<? extends类或接口>类似,这个约束也可以理解为泛型的上界

  • 例如泛型约束<T:BoundingType>,其中BoundingType可以称为绑定类型,绑定类型可以是类或者接口。如果绑定类型是一个类,则类型参数T必须是BoundingType的子类。如果绑定类型是一个接口,则类型参数T必须是BoundingType接口的实现类

  • 如果上界约束需要多个约束,则可以通过where语句来完成

  • <T:Any?>表示类型实参是Any的子类,且类型实参可以为null

  • <T:Any>表示类型实参是Any的子类,且类型实参不可以为null

  • 子类是继承的概念,如果B继承A,则B就是A的子类。如果需要使用类型A的变量时,可以使用类型B的变量来代替,则此时类型B就是A的子类型。

  • 子类与子类型是不同的,类中变量的替换原则只适合于子类型关系

  • 子类说明是一个新类继承了父类,而子类型则是强调了新类具有父类一样的行为,这个行为不一定是继承

  • 如果B类实现了接口A,则B类就是接口A的子类型

  • 非空类型String是可空类型String?的子类型

  • B是A的子类型,但Xxx<B>不是Xxx<A>的子类型

协变与逆变

  • out关键字用于指定该类型参数是协变Covariant;in关键字用于指定该类型参数是逆变Contravariance

  • 协变是将父类变为具体子类,协变类型作为消费者,只能读取不能写入,逆变是将子类变为具体父类,逆变作为生产者,只能写入不能读取

  • B类是A类的子类型,默认情况下Xxx<B>不是Xxx<A>的子类型。但是通过out关键字可以使Xxx<B>是Xxx<A>的子类型,这样的操作叫作协变

  • out关键字只能出现在泛型类或者泛型接口的泛型参数声明上,不能出现在泛型方法的泛型参数声明上

  • out关键字修饰泛型类或者泛型接口的泛型参数时会支持协变

  • in关键字与out关键字有相反的功能,可以使Xxx<A>不是Xxx<B>的子类型,这样的变化叫作逆变

  • in关键字可以出现在泛型类型或者泛型接口的泛型参数声明上,不能出现在泛型方法的泛型参数声明上

  • in关键字修饰泛型类或者泛型接口中的泛型参数时会支持逆变

  • 泛型参数T在使用了in关键字之后,不能声明成val或者var类型的变量

  • 除了在类或接口中定义泛型参数时使用out、in关键字之外,还可以在泛型参数出现的具体位置使用out、in关键字,这种变型被称为使用点变型

泛型擦除与实化类型

  • 擦除是指当定义一个泛型时,例如List<String>类型,运行时它只是List,并不体现String类型

  • 在Java程序中,如果不知道泛型的具体类型时,可以用“?”通配符来代替具体的类型,而在Kotlin中则使用“”来代替泛型的具体类型,这个“”就被称为泛型通配符,它只能在“<>”中使用

  • 星投影就是将泛型中的“*”等价于泛型中的注解out与in对应的协变类型参数与逆变类型参数,泛型的每个具体实例化将是该投影的子类型

  • 对于泛型类A<out T>,其中T是一个具有上界TUpper的协变类型参数,A<>等价于A<out TUpper>,这意味着当T未知时,可以安全地从A<>中读取TUpper的值。

  • 对于泛型类A<in T>,其中T是一个逆变类型参数,A<>等价于A<in Nothing>,由于Nothing类型表示没有任何值,因此这意味着当T未知时,没有安全的方式写入A<

  • 对于泛型类A<T>,其中T是一个具有上界TUpper的不型变类型参数,A<*>在读取值时等价于A<outTUpper>,而在写值时等价于A<in Nothing>

  • 如果泛型类型具有多个类型参数,则每个类型参数都可以进行单独的星投影,例如,如果声明一个泛型类B<inT,out U>,则此时可以根据星投影语法推测出以下星投影。

  • 如果泛型类为B<*, String>,则该泛型类等价于B<inNothing, String>。

  • 如果泛型类为B<Int,*>,则该泛型类等价于B<Int, outAny?>。

  • 如果泛型类为B<,>,则该泛型类等价于B<inNothing, out Any?>。

  • 在Java中,可以通过反射获取泛型的真实类型,而在Kotlin中,要想获取泛型的实参类型,则需要在内联函数(inline关键字定义的函数)中使用reified关键字修饰泛型参数才可以,这样的参数称为实化类型

  • reified关键词必须要和inline一起使用,因为只有内联的泛型函数才可以在运行时获取泛型实参的类型

Kotlin

相关文章

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

  • 【Swift】泛型常见使用

    1、Swift泛型4种 泛型函数泛型类型泛型协议泛型约束 2、泛型约束3种 继承约束:泛型类型 必须 是某个类的子...

网友评论

      本文标题:泛型

      本文链接:https://www.haomeiwen.com/subject/gzgvnhtx.html