探索 Java & Kotlin 泛型

本文深入探讨了Kotlin和Java的泛型,包括基础、擦除、约束、协变与逆变、类型投影、星投影以及具体化类型参数。通过示例解释了泛型在实际编程中的应用,如在Kotlin中使用声明处型变和内联函数实现类型安全。文章适合想要提升Kotlin和Java泛型理解的开发者阅读。
摘要由CSDN通过智能技术生成

Kotlin 泛型基础

泛型可以让我们在代码中声明类型参数,Kotlin 泛型最基本的使用和 Java 一样,可以声明在类上和函数上,用法也都差不多。

  • 声明在函数上时,可将类型参数作为参数或返回值的类型,该函数为泛型函数
  • 声明在类上时,可以用在任意一处类型声明处,该类为泛型类
class GenericsDemo<T>(t: T) {
   
    val value = t
}

fun <T> invoke(t: T) : T {
   
    return t
} 

我们可以在声明了类型参数的类中,声明一个泛型方法,但如果内部方法所声明的类型参数名称和类上所声明的相同,那么会覆盖类上所声明的类型参数。下面的代码不会报错,并会打印 Hello 字符串。

class GenericsDemo<T>() {
   

    fun <T> invoke(t: T) : T {
   
        return t
    }
}

val demo = GenericsDemo<Int>()
println(demo.invoke("Hello")) 

此外,我们知道在类中可通过重载来定义同名方法,但这在泛型中并不起作用,如果类中拥有以下两个方法,那么将会报错。

class GenericsDemo<T>() {
   

    // 泛型来自类
    fun invoke(t: T) : T {
   
        return t
    }

    // 泛型来自方法本身
    fun <S> invoke(s: S) : S {
   
        return s
    }
} 

上诉代码报错原因是因为两个方法拥有相同的 signature,也就是在 JVM 看来这两个方法的方法名和参数都是一样的,报错信息如下:

Platform declaration clash: The following declarations have the same JVM signature (invoke(Ljava/lang/Object;)Ljava/lang/Object;):

造成上诉_参数类型覆盖_和_重载签名相同_的原因是在编译成 .class 文件后,类型参数会被擦除。

泛型擦除

Java 和 Kotlin 的泛型都是伪泛型,泛型所进行的类型安全检查仅在编译器进行,在进入 JVM 时这些类型参数都会被移除,运行时不会保留和类型参数相关的信息,我们称这种机制为泛型擦除

由于泛型是在 JDK 1.5 才引入,为了兼容之前的版本,因此采用泛型擦除来移除运行时的类型参数

泛型擦除时,被擦除的类型参数都会被替换成 Object,这也是为什么上述 invoke() 方法的 signature 为 invoke(Ljava/lang/Object;)Ljava/lang/Object;

如果该报错来自 IDEA,它可能会提示采用 @JvmName 注解来处理这个问题,这可以改变编译成字节码后该方法的名称。

@JvmName("invoke1")
fun <S> invoke(s: S) : S {
   
    return s
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值