泛型

作者: 苏格拉第 | 来源:发表于2018-12-26 10:42 被阅读0次

Kotlin 泛型详解

声明一个泛型类

class Box<T>(t: T) {
    var value = t
}

声明一个泛型方法

fun <T> requestT(t: T) {

}

泛型约束

List<Int> 和 List<Number> 是没有关系的。
在Java中可以用泛型约束定义这种关系。

fun <T : Comparable<T>> sort(list: List<T>) {
    // ……
}

对于多个上界约束条件,可以用 where 子句:

fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
    where T : CharSequence,
          T : Comparable<T> {
    return list.filter { it > threshold }.map { it.toString() }
}

型变

Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。

声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。

  • in 消费者(接受T 作为参数)
// 定义一个支持逆变的类
class Runoob<in A>(a: A) {
    fun foo(a: A) {
    }
}

fun main(args: Array<String>) {
    var strDCo = Runoob("a")
    var anyDCo = Runoob<Any>("b")
    strDCo = anyDCo
}

out 生产者(接受T 作为返回值)

// 定义一个支持协变的类
class Runoob<out A>(val a: A) {
    fun foo(): A {
        return a
    }
}
public fun addAll(elements: Collection<E>): Boolean

而Collection 是型变的

public interface Collection<out E> : Iterable<E> {
  • 对应的是Java中的
boolean addAll(Collection<? extends E> c);

通配符

在Java 中,当我们不知道泛型具体类型的时候可以用 ?来代替具体的类型来使用,比如下面的写法:

 Class<?> cls = numbers.getClass(); 

* 在哪些场合下可以或者不可以使用呢?

 fun <T> hello(args: Array<T>){ 
     ... 
 } 
   
 ... 
 hello<*>(args) // ERROR!! 

* 不允许作为函数和变量的类型的泛型参数!

 interface Foo<T> 
   
 class Bar : Foo<*> // ERROR! 

* 不能直接作为父类的泛型参数传入!

   
 class Bar : Foo<Foo<*>> 

这是正确的。注意,尽管 * 不能直接作为类的泛型参数,Foo<*> 却可以,按照前面官方给出的说法,它在读时等价于Foo<out Any> 写时等价于 Foo<in Nothing>

 fun hello(args: Array<*>){ 
     ... 
 } 

同样,这表示接受的参数的类型在读写时分别等价于Array<out Any> 和 Array<in Nothing>

原生类型

Java中原生类型是为了向后兼容

 List list = new ArrayList(); 

在kotlin这种代码是不被编译器允许的

val list = ArrayList() //Error
 val list = ArrayList<Any?>()  //right

但上面 ArrayList<Any?>()不是协变的

 var list = ArrayList<Any?>() 
 val integers = ArrayList<Int>() 
 list = integers // ERROR!

类型擦除

从运行时的角度看Java与kotlin是类型擦除的。
考虑下面的代码:

List<String> l1 = new ArrayList<>();
 List<Integer> l2 = new ArrayList<>();

System.out.print("l1 class:" + l1.getClass()+ "\n");//print class:class java.util.ArrayList
System.out.print("l2 class:" + l2.getClass() + "\n"); //print class:class java.util.ArrayList
assertEquals(l1.getClass(), l2.getClass());

最终结果测试通过,输出都为: class:class java.util.ArrayList

在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 <T> 则会被转译成普通的 Object 类型,如果指定了上限如 <T extends String> 则类型参数就被替换成类型上限。

Reference:
菜鸟教程-泛型
Kotlin 泛型详解
Java 泛型,你了解类型擦除吗?

相关文章

  • 泛型 & 注解 & 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/rtpzkqtx.html