首页 > 其他分享 >kotlin 泛型的类型擦除和实化类型参数

kotlin 泛型的类型擦除和实化类型参数

时间:2023-12-12 23:23:13浏览次数:28  
标签:fun kotlin List 实化 类型 擦除 value 泛型 printSum

JVM上的泛型一般是通过类型的擦除实现,就是泛型类实例的类型实参在运行时不保留。

但是可以通过声明为inline函数使其类型实参不被擦除

那么对类型擦除有啥好处呢?应用程序使用的内存总量较小,因为要保存在内存中的类型信息更少。

一、类型检查和转换

1、类型检查

因为类型会被擦除,那么需要知道是否包含了某种类型的元素是否可以呢?

fun <T> testType(value: List<T>) {
    if (value is List<String>) { // 这里会提示错误:Cannot check for instance of erased type: List<String>
        
    }
}

如上所述,没办法明确判断是否是List<String>,我们只能够判断它是List;但是这里也会提示:Check for instance is always 'true',因为只判断了List没有得到元素类型的相关信息

fun <T> testType(value: List<T>) {
    if (value is List<*>) { // 使用*表示任意类型

    }
}

如果是确定类型的话,则可以做出正确的判断,如下指定了Int元素类型,对应的集合也都是父子关系

fun printSum(c: Collection<Int>) { // 这里明确元素类型是Int
    if (c is List<Int>) { // 这里则可以正确判断是否是Int类型,对应的集合如果是List或者List的子类都能够被正常判断
        println(c.sum())
    }
}

printSum(listOf(1,2,3))
printSum(mutableListOf(1,2,3))

如上函数的参数的集合是Collection,是所有集合的父类

 

2、类型转换

这里通过as或as?进行类型的转换

fun printSum(c: Collection<*>) {
    val intList = c as? List<Int> ?: throw IllegalArgumentException("list error")
    println(intList.sum())
}

接下去对该函数的调用

    println(printSum(listOf(1,2,3)))
    println(printSum(listOf("a"))) // 类型推导失败导致intList.sum()调用的时候抛出异常:class java.lang.String cannot be cast to class java.lang.Number
    println(printSum(setOf(1))) // 因为不是list 则在as时候则会失败,并抛出:throw IllegalArgumentException("list error")这个异常

通过如上的类型推导能够发现:as类型转换之后,其实能够识别的也只是List,对应的<Int>类型还是没有识别出来,要到调用的时候才会因为没有对应的sum才抛出异常。

 

3、内联函数能够做到类型避免擦除,即他们的类型参数被实化

编译器会在调用内联函数的位置替换成函数实际的代码实现。那么类型参数被实化成为了可能

// 如下是内联函数,但是还是会提示错误:Cannot check for instance of erased type: T
// 依旧是擦除的情况
inline fun <T> isA(value: Any) = value is T

// 改为在T上面增加reified的标记
inline fun <reified T> isA(value: Any) = value is T

 具体的解释:编译器把实现内联函数的字节码插入每一次调用发生的地方。每次你调用带实化类型参数的函数时,编译器都知道这次特定调用中用作类型实参的确切类型。因此,编译器可以生成引用作为类型实参的具体类的字节码。

标签:fun,kotlin,List,实化,类型,擦除,value,泛型,printSum
From: https://www.cnblogs.com/czwlinux/p/17835490.html

相关文章

  • kotlin<第一篇>:入门
    一、main和打印funmain(){println("HeloKotlin")}kotlin中,新建一个main函数可以调试kotlin程序,println函数可以将结果输出到控制台。二、常量和变量val:只读变量(只读,不可变化)var:变量constval:常量常量不能在函数中使用,只能在方法外面使用,比如:constvalUSERNAME:St......
  • 高效的 Json 解析框架 kotlinx.serialization
    一、引出问题你是否有在使用Gson序列化对象时,见到如下异常:Abstractclassescan'tbeinstantiated!RegisteranInstanceCreatororaTypeAdapterforthistype.什么时候会出现如此异常。下面举个栗子:importcom.google.gson.Gsonimportcom.google.gson.reflect.Type......
  • C#泛型编程:深入探究泛型的威力
    文章目录泛型(Generic)泛型(Generic)的特性泛型约束派生约束构造函数约束值约束引用约束多个泛型参数泛型类继承泛型约束泛型方法泛型方法的重载泛型方法的重写虚方法泛型泛型委托泛型强转泛型参数隐式强制转换泛型参数显示强制转换泛型参数强制转换到其他任何类......
  • 第一节 Kotlin基础
    Kotlin基础简介主要介绍:开发环境的搭建Kotlin基本语法Kotlin参考Kotlin源代码网址:https://github.com/JetBrains/kotlinKotlin官网:https://kotlinlang.orgKotlin官方参考文档:https://kotlinlang.org/docs/referencekotlin标准库:https://kotlinlang.org/api/latest/......
  • 用Kotlin抓取微博数据并进行热度预测
    闲来无事,逛逛微博,看着每条热度很高的博文趣事,心想能否通过爬虫抓取微博热度并进行趋势分析,说干就干,这里需要注意的问题我会一一标注。爬虫ip信息的设置是在爬虫程序中进行的。爬虫ip信息可以帮助爬虫程序在访问目标网站时进行匿名化处理,以避免被目标网站检测到并封禁IP。以下是一......
  • golang之泛型
    Go1.18版本增加了对泛型的支持,泛型也是自Go语言开源以来所做的最大改变。 泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。ーー换句话说,在编写某些代码或数据结构时先不提供值的类型,而是之后再提供。泛型是一种......
  • 【Cpp 基础】泛型算法 stable_sort() 的应用
    最近在刷牛客的题。经常遇到排序问题,经常有一个附加的规则:相同的数值的,按照录入的顺序排序。可是C++的sort()的底层是快速排序,并不能保证相同数值的顺序不改变。所以最后我不得不自己写冒泡排序。(冒泡排序不改变相同数值的录入顺序)写了那么多的排序,但是其实C++里封装有排序函数......
  • kotlin协程和java线程有啥区别
    Kotlin协程相对于Java线程有一些优势,尤其在处理异步和并发任务时,提供了更加简洁、可读性更高的代码。以下是一些Kotlin协程相比于Java线程的优势:轻量级:协程是轻量级的,可以更高效地创建和销毁,不需要像线程那样消耗大量的系统资源。更好的可读性:使用协程可以避免......
  • Golang 泛型及代码示例
    以下是一个包含Golang泛型代码示例的文件:packagemainimport("fmt""sort")//泛型函数funcAdd[Tany](x,yT)T{returnx+y}funcmain(){//将两个整数相加fmt.Println(Add(1,2))//3//将两个字符串相加fmt.Println(Add(......
  • Kotlin Notes - 6
    Toaccessthisfromanouterscope(aclass,extensionfunction,orlabeledfunctionliteralwithreceiver)youwritethis@label,where@labelisalabelonthescopethisismeanttobefrom:classA{//implicitlabel@AinnerclassB{//implicit......