kotlin 泛型out是什么??

Kotlin泛型<in, out, where>概念及示例 在 Kotlin 中,泛型用于指定类、接口或方法可以操作的对象类型。 阅读详情

kotlin 泛型out是什么??

前言:

   今天在阅读第三方框架底层源码时,用kotlin写的。遇到 <out : 类名> ,当时就在想这是啥? 我知道Java里面定义限定类型用的是 <T extends 类名>, 用的通配符类型是 <? extends 类名> ,<? super 类名>.。于是带着这个疑惑,去kotlin官方文档去查了一下泛型。并巩固了一下泛型的知识。

主要分几个部分来总结一下:

1. 泛型的定义

  • 泛型类
       在kotlin里面定义泛型,只需要在类的后面加上<> 即可,里面定义泛型 T、M、K 等等,如下面:
 /**
 *  @description 泛型类的定义
 *  @author 陈元
 *  @date  2020 07/11
 */
class Generate<T>(var t:T)

 /**
 *  @description 泛型类定义多个泛型
 *  @author 陈元
 *  @date  2020 07/11
 */
class GenerateMore<T,K>(val t:T,val k:K)
  • 泛型接口
    泛型接口和泛型类的定义语法没多大变化,都是在名字后面加 <>
 /**
 *  @description 泛型接口的定义
 *  @author 陈元
 *  @date  2020 07/11
 */
interface GenerateInter<T>{
     //使用传过来的泛型
     fun useT(t:T)
}

 /**
 *  @description 泛型接口,定义多个泛型
 *  @author 陈元
 *  @date  2020 07/11
 */
interface GenerateInterMore<T,M>{
     //使用传过来的泛型
     fun useT(t:T)
     //使用传过来的多个泛型
     fun useTM(t:T,m:M)
}
  • 泛型方法
/**
 * 4.泛型方法
 */
fun <T> generate(t:T){
     println()
}

/**
 * 4.定义多个泛型
 */
fun <T,L> generateMore(t:T,l:L){
     
}

好了,以上就是泛型的定义。

2. 泛型的限定类型变量

通过名字就知道,限定类型,即然是限定类型,那么肯定是限定在某一个类型之内,不能超过。
为了演示这个限定类型,我们来定义几个类。几个类的关系如图
在这里插入图片描述
代码示例:

/**
 *  @description 水果
 *  @author 陈元
 *  @date  2020 07/11
 */
open class Fruit{

   open fun name(){
        println("水果父亲")
    }
}
/**
 *  @description 苹果
 *  @author 陈元
 *  @date  2020 07/11
 */
open class Apple : Fruit() {

    override fun name() {
        println("苹果")
    }
    
}
/**
 *  @description 香蕉
 *  @author 陈元
 *  @date  2020 07/11
 */
class Banana : Fruit() {
    override fun name() {
        println("香蕉")
    }
}
/**
 *  @description 小苹果
 *  @author 陈元
 *  @date  2020 07/11
 */
class SmallApple : Apple() {
    override fun name() {
        println("小苹果")
    }
}

代码非常简单,我们在使用泛型类型限定。首先说一下语法 定义泛型时,使用 <T :类名>,具体如下

/**
 * 1.泛型的类型限定
 */
class Generate<T:Apple>(var t:T)

通过这里,大家可以看到,我们在定义泛型T时,限定了我们传入的T只能是Apple类型,包括Apple的所有的孩子。
我们来测试下吧!

	//因为限定了类型,所以传String是不行的
    val generate = Generate("apple")
    
    // 传入apple肯定可以,这点我们都知道
    val generate2 = Generate(Apple())

    //虽然Apple是派生自Fruit,这里传入Fruit依然不行
    val generate1 = Generate(Fruit())
    
    //这边传入Apple的孩子,也是可以的
    val generate3 = Generate(SmallApple())

有人读到这里,说Java里泛型不仅可以限定一个类型,还可以限定多个类型,我们这里当然也是可以的了,我们来看看

**
 *  @description 泛型限定
 *  @author 陈元
 *  @date  2020 07/11
 */

/**
 * 1.泛型的类型限定,限定多个类型
 */
class Generate<T>(var t:T) where T:Apple,T:Serializable

使用呢,是不是都符合,我们的期望,这里我们限定的两个类型
**

  • 1.限定必须是Apple类型,或派生自Apple
  • 2.限定必须实现了Serializable序列化接口

**
我们测试一下吧
这里我们先试一下,没有实现Serial… 这个接口的,

  // 传入apple肯定可以,这点我们都知道
    val generate4 = Generate(Apple())

我们运行,发现编译器报错了
e: Test.kt: (21, 21): Type parameter bound for T in constructor Generate(t: T) where T : Serializable
is not satisfied: inferred type Apple is not a subtype of Serializable

看到这个错,都知道了吧。这边同时还需要实现Serializable 接口,就可以了。

泛型接口,和 泛型方法,在使用的时候,类型限定都是一样的,这里就不一一展开了,大家可以去阅读官方文档哦。
官方文档地址

3. 泛型的继承规则

这边直接上代码解释,我们在使用泛型或设计框架时,泛型在使用泛型类时去继承异常,编译器直接报错,是无法使用的。以下就是 典型的错误的例子。

class GenerateTException<T> : Exception()

class GenerateTException2<T> : Throwable()

这里再说明一下,我们在使用泛型时,比如前面提到的 Apple 派生自 Fruit。本来在使用的时候是没有任何问题的。如下

val fruit:Fruit = Apple()

但是在使用泛型时,要注意,以下是错误代码

val generate:Generate<Fruit>  = Generate<Apple>(Apple())

虽然在apple 是派生自水果,但是水果 Generate<> 和 苹果 Generate<> 是没有任何关系的。

4. 泛型的通配符类型(只读/只写模式)

本文的重点来了,out 和 in 这两个 原来是 java 里的 《?extends 类名》 和 《?super类名》
这边呢,咱们直接上代码解释
out
1.首先,我们定义一个泛型,如下:

 /**
 *  @description 泛型
 *  @author 陈元
 *  @date  2020 07/11
 */
 class Generate<T>(var t:T)

2.我们再定义一个方法,来使用泛型的通配符类形

fun generateFunc(generate:Generate<out Apple>){
    println(generate.t.name())
}

这个方法的意思是,我接收一个Generate类型的参数,里面的泛型 out Apple表示,我这里接收的泛型只能是Apple和Apple的孩子或孙子。。,如代码所示:

  val generate = Generate(Fruit())

    val generate1 = Generate(Apple())

    val generate2 = Generate(SmallApple())
   generateFunc(generate) //这里报错,说明不可以传入 Fruit
   generateFunc(generate1)
    generateFunc(generate2)

只读模式
为什么这里,是只读模式呢,因为,在方法里面我们调用 generate.t.name() 这个方法的时候,我们可以获取。 但是如果我们,去重新赋值是不行的,如下

fun generateFunc(generate:Generate<out Apple>){
    generate.t = SmallApple() //这句话报错,只能读,不能重新赋值,
    println(generate.t.name()) 
}

in

现在,我们就把方法里面的out 换成 in,再来看看我们的调用

 val generate = Generate(Fruit())

    val generate1 = Generate(Apple())

    val generate2 = Generate(SmallApple())
   generateFunc(generate) 
   generateFunc(generate1)
    generateFunc(generate2) //这里报错,说明不可以传入 smallApple也就是孩子

里面的泛型 in Apple表示,我这里接收的泛型只能是Apple和Apple的父亲或爷爷。。。
只写模式

fun generateFunc(generate:Generate<in Apple>){
    generate.t = SmallApple() 
    println(generate.t.name()) //这句话报错,只能写,不能读,
}

5. 泛型的底层原理,虚拟机如何实现泛型?

知道了,泛型的使用后,知道泛型好神奇呀,那我们再看一看,一起探究一下,泛型底层的原理到底是怎么实现的,虚拟机是如何实现泛型的。我们还是通过代码来看看,如下

/**
 *  @description 探究泛型的底层原理
 *  @author 陈元
 *  @date  2020 07/11
 */
fun main() {

    val generate = Generate(Fruit())

    val generate1 = Generate(Apple())

    println(generate.javaClass)
    println(generate1.javaClass)
    println(generate.javaClass == generate1.javaClass)

}

这边我们简单起见,就定义了两个类,然后我们输出genrate和generate1的class类型对象,得出来结果如下:

G:\androidStudio\Android\jre\bin\java.exe -javaagent:G:\androidStudio\Android\lib\idea_rt.jar=58896:G:\androidStudio\Android\bin -Dfile.encoding=UTF-8 -classpath G:\androidStudio\AndroidStudioSDk\platforms\android-29\android.jar;G:\androidStudio\AndroidStudioSDk\platforms\android-29\data\res;F:\android-eclipse-workspace\MyApplication\app\build\intermediates\javac\debug\classes;F:\android-eclipse-workspace\MyApplication\app\build\tmp\kotlin-classes\debug;F:\android-eclipse-workspace\MyApplication\app\build\generated\res\resValues\debug;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-android-extensions-runtime\1.3.50\bec16087637a7cafe54894e73d38037977cb30d2\kotlin-android-extensions-runtime-1.3.50.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-jdk7\1.3.50\50ad05ea1c2595fb31b800e76db464d08d599af3\kotlin-stdlib-jdk7-1.3.50.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib\1.3.50\b529d1738c7e98bbfa36a4134039528f2ce78ebf\kotlin-stdlib-1.3.50.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-common\1.3.50\3d9cd3e1bc7b92e95f43d45be3bfbcf38e36ab87\kotlin-stdlib-common-1.3.50.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.jetbrains\annotations\13.0\919f0dfe192fb4e063e7dacadee7f8bb9a2672a9\annotations-13.0.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\androidx.collection\collection\1.1.0\1f27220b47669781457de0d600849a5de0e89909\collection-1.1.0.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\androidx.lifecycle\lifecycle-common\2.1.0\c67e7807d9cd6c329b9d0218b2ec4e505dd340b7\lifecycle-common-2.1.0.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\androidx.arch.core\core-common\2.1.0\b3152fc64428c9354344bd89848ecddc09b6f07e\core-common-2.1.0.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\androidx.annotation\annotation\1.1.0\e3a6fb2f40e3a3842e6b7472628ba4ce416ea4c8\annotation-1.1.0.jar;C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\androidx.constraintlayout\constraintlayout-solver\1.1.3\54abe9ffb22cc9019b0b6fcc10f185cc4e67b34e\constraintlayout-solver-1.1.3.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\b8f10ae6f5b38c660c7334f34edc8667\core-ktx-1.2.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\31016c6c0856b517b84ecfbcfb815ff0\appcompat-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\31016c6c0856b517b84ecfbcfb815ff0\appcompat-1.1.0\res;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\6ad38dfac4e106a4ff4e5e048c9d7854\cursoradapter-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\9c96e3c7610a71f64d933abf5d989c41\fragment-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\3c6026bf367a81ae0b26f6a0755e7c5c\appcompat-resources-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\3c6026bf367a81ae0b26f6a0755e7c5c\appcompat-resources-1.1.0\res;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\9eeb03172080be4be809eb3b789602a2\drawerlayout-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\d81313297acd4b62a12e1c4be346ea86\viewpager-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\d4d6f1b618f6740b3852fbc0a4f6708f\loader-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\47bf1c1672b530aea741a2298486de75\activity-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\8042381f1240df5f98ac8c5a464644dd\vectordrawable-animated-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\2485cb75ca766726d2f85318526894e3\vectordrawable-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\b403c837ac7d55e559d7b654aa580176\customview-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\415a936aa630178fa8f04bbb1a3bb075\core-1.2.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\415a936aa630178fa8f04bbb1a3bb075\core-1.2.0\res;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\5aa6e1ee8a4aa87ed09e4136bb1359d6\versionedparcelable-1.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\8be5234bafda9ab14ed7f88c9dd40d77\lifecycle-viewmodel-2.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\d5a39d8f51fcfc1b19c3ec4132b72e21\lifecycle-runtime-2.1.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\621e01429d79a08e6530f2907ad873bf\savedstate-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\e05a230acf535e3dec39f0f39ed5f0ca\interpolator-1.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\004fb91108e1b1927119709e2ff43030\lifecycle-livedata-2.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\3a3ed459510bf208b94d56b861c80196\lifecycle-livedata-core-2.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\ab93a8dbadb16e1d4464b7fe897665b9\core-runtime-2.0.0\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\c4b4b829cc770abdd306eef91b3e77f9\constraintlayout-1.1.3\jars\classes.jar;C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\c4b4b829cc770abdd306eef91b3e77f9\constraintlayout-1.1.3\res com.myapplication.TestKt
class com.myapplication.Generate
class com.myapplication.Generate
true

Process finished with exit code 0

这就尴尬了,明明是两个对象,为什么拿到的class对象为同一个呢。我们带着这个疑问,继续深究,我们去看一下底层的字节码 如下

 public final static main()V
   L0
    LINENUMBER 8 L0
    NEW com/myapplication/Generate
    DUP
    NEW com/myapplication/Fruit
    DUP
    INVOKESPECIAL com/myapplication/Fruit.<init> ()V  //这边首先初始化了Fruit
    INVOKESPECIAL com/myapplication/Generate.<init> (Ljava/lang/Object;)V  //这边初始化Generate时泛型的类型 竟然是object.
    ASTORE 0
   L1
    LINENUMBER 10 L1
    NEW com/myapplication/Generate
    DUP
    NEW com/myapplication/Apple
    DUP
    INVOKESPECIAL com/myapplication/Apple.<init> ()V
    INVOKESPECIAL com/myapplication/Generate.<init> (Ljava/lang/Object;)V
    ASTORE 1

我嚓,我嚓,什么鬼,我们看一下, 请看注释处,我们首先初始化了Fruit对象,然后我们初始化对象Generate 时,泛型变成Objcet了。再一看呢,最后第二行,初始化对象Generate时 泛型同样也变成Object了
泛型嚓除
原来虚拟机在实现泛型的时候,先把类型给嚓除了,变成了Object .

Kotlin 泛型 协变out 和 逆变 in 及Java中extends和super的对比 List<? extends TextView> textViews = new ArrayList<TextView>(); TextView textView = textViews.get(0); //确定可以获取到TextView(根据多态是其子类也会向上转型,所以可以) textViews.add(new Button(this)); //报错 textViews.add(new Vi... 阅读详情

相关推荐

Windows 10/11 零基础配置 SillyTavern 连接 Claude API 完整指南(含 Node.js 环境搭建)

本文提供Windows 10/11系统下零基础配置SillyTavern连接Claude API的完整教程,涵盖Node.js环境搭建、SillyTavern初始化及API连接配置等关键步骤。通过详细的操作指南和实用技巧,帮助用户快速搭建AI聊天界面并优化对话体验,实现与Claude AI的高效交互。

weixin_30642561的博客 134

kotlin语言中的out和in

kotlin语言中的out和in

转载和创作优秀的博客 3505

Demo2Reward:用人类演示动态优化VLM奖励模型提示

多模态大模型(VLM)的奖励建模正面临核心瓶颈——静态提示导致语义鸿沟与泛化失效。其本质是将人类判断标准固化为不可更新的文本模板,使奖励信号脱离真实任务意图。Demo2Reward提出范式级改进:以结构化人类演示为元信号,驱动提示权重连续优化,实现从‘结果打分’到‘过程理解’的跃迁。该方法不修改VLM主干,却显著提升RLHF收敛效率与OOD鲁棒性,在医疗、工业质检等场景验证了跨任务迁移与热修复能力。它重新定义了提示工程的技术价值:不是前端微调,而是奖励系统的认知校准基础设施。

weixin_34302798的博客 408

kotlin泛型、以及in、out关键字的作用

无论是在类、还是在方法中,<T>泛型占位符的定义都只表示这个类/方法支持泛型,并不是表示这个类/方法的返回值和属性都被定义为泛型。也就是说即是使用<T>修饰,你同样可以使用基本类型作为属性和返回值。//最简单的泛型类格式//泛型类支持泛型属性//还可以支持泛型方法//方法体//支持泛型参数的方法//方法体//返回泛型的方法//方法体//多泛型,此处只做入门讲解,多泛型不做深入//方法体。

qq_53376963的博客 1549

避坑指南:Qwen2.5-VL图片预处理中常见的5个尺寸错误

本文深入解析了Qwen2.5-VL模型在图片预处理环节中开发者最常遇到的五个尺寸错误,包括动态分辨率对齐、宽高比超标、像素数限制等问题。文章结合源码解读,详细剖析了`process_vision_info`函数和`resize`逻辑,并提供了具体的排查流程图与参数设置建议,旨在帮助开发者构建健壮的预处理流水线,有效规避显存溢出与推理失败的风险。

weixin_29290379的博客 176

开源CMDB与资产管理平台对比报告

本文对比分析了9款主流开源CMDB平台,从集成能力、功能完整性和多语言支持三个维度进行评测。重点介绍了VeCMDB、蓝鲸CMDB、WeCMDB和OpsAny等国产平台的特色:VeCMDB以动态模型和自动发现见长;蓝鲸CMDB适合超大规模企业级应用;WeCMDB专注金融级高并发场景;OpsAny提供一体化运维解决方案。针对不同规模企业给出选型建议:中小团队推荐Snipe-IT等轻量工具;大型企业建议蓝鲸或WeCMDB;需国产化适配的可选VeCMDB或OpsAny。文章还特别指出iTop、GLPI等适合ITIL

huang0612123的博客 1080

Kotlin中接口、抽象类、泛型、out(协变)、in(逆变)、reified关键字的详解

一、Kotlin中接口的定义。四、out协变和in逆变详解。五、reified关键字。

路宇的博客 736

安卓ai自动化脚本 Yyds.Auto实现 示例 纯ai图像识别自动点击脚本

纯ai识别实现自动化脚本

专注安卓前沿科技 4782

Kotlin 泛型中的 in 和 out

当我们在 Kotlin 中定义泛型时,我们会发现它需要使用到 in 和 out 两个关键字来定义。从形式上来讲,这是一种定义「逆变」和「协变」的方式。 那啥叫逆变?啥叫协变?可以参考下维基百科的定义:协变与逆变 in & out 怎么记? out(协变) 如果泛型类只将泛型类型作为函数的返回(输出),那么使用 out: interface Production<out T> {...

明年今日zhich 6920

计算机毕设项目十四:美团酒店评论情感分析完整数据代码-可直接运行

计算机毕设项目十四:美团酒店评论情感分析完整数据代码-可直接运行

693

【深度学习|语义分割之UNet】如何使用ResNet50 作为 U-Net 网络的骨干网络(backbone)并使用预训练的 ResNet50 模型。附代码及解读。

【深度学习|语义分割之UNet】如何使用ResNet50 作为 U-Net 网络的骨干网络(backbone)并使用预训练的 ResNet50 模型。附代码及解读。

985小水博的摸鱼日常 3091

【编程语言】Kotlin快速入门 - 泛型

Java工程师Kotlin快速入门之泛型

XuanRan的博客 5024

【Simulink教程案例9】基于simulink的BPSK,QPSK调制解调通信系统建模与仿真——使用simulink自带模块设计

BPSK (Binary Phase Shift Keying)-------二进制相移键控。是把模拟信号转换成数据值的转换方式之一,利用偏离相位的复数波浪组合来表现信息键控移相方式。BPSK使用了基准的正弦波和相位反转的波浪,使一方为0,另一方为1,从而可以同时传送接受2值(1比特)的信息。BPSK的映射关系如下所示:BPSK调制过程将输入的1010二进制数据中的0都转化为-1,使得非极性码变为极性码。

FPGA/MATLAB学习教程/源码/项目合作开发 3486

Kotlin 泛型

Kotlin 泛型定义、where 约束、内联具象化泛型函数、in 和 out。

Chanwing Chow的博客 1115

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

如何理解Kotlin泛型中的in和out?

1.引言 Kotlin中的泛型使用和java一样,但如果你使用的是kotlin语言开发,你会发现kotlin的泛型会多出两个关键字,分别是in和out。这两个关键字经常让人疑惑,它的字面意思是输入和输出,很难让人联想到java泛型的某个特性。实际上它们在java中是有对应关系的。 2.java中的泛型通配符 为了更好的理解in、out关键字的作用,我们需要对比java的泛型通配符来看。 先定义一个类: public class Stack<E>{ void push(E e){..

养生阿华田 2717

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Android 之 Kotlin 泛型中的out和 in

Kotlin泛型中的out和in关键字用于控制类型参数型变,分别实现协变和逆变。out用于生产者角色,只允许类型参数出现在输出位置(如返回值),确保安全读取;in用于消费者角色,只允许类型参数出现在输入位置(如参数),确保安全写入。out使子类泛型可赋给父类泛型(List<String>到List<Any>),in则相反(Consumer<Any>到Consumer<String>)。通过限制输入输出位置,编译器在保证类型安全的同时实现灵活的泛型赋值。核心记忆

早日成为鹏总 1368

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java与Kotlin中的泛型之:擦除、不变、协变、逆变

本文深入探讨了Java与Kotlin中泛型的关键特性,包括类型擦除、不变性、协变与逆变。通过实例解析了Java泛型类型擦除的机制及其对代码兼容性的影响,同时对比了Kotlin中泛型对数组的支持及协变逆变的应用。文章详细阐述了泛型不变性的概念,并通过Kotlin的out和in关键字展示了协变与逆变的具体实现方式,以及如何通过@UnsafeVariance注解解除协变逆变的限制。此外,还介绍了Kotlin内联函数在获取泛型参数类型中的应用,为深入理解Java与Kotlin泛型提供了全面视角。

zyj13617的博客 2531

类比学习——java 泛型& kotlin 泛型中的 in out where

在学习 kotlin 泛型的时候,经常会遇到 in out 这两个词,一会用in 一会用out,为啥这里要用 out ?为啥哪里用 in ?啥什么用 out 啥时候用in ?对应上面问题以前我是晕乎乎的,不是很明白,于是打算写这篇文章梳理一下,搞清楚怎么回事。 Java 泛型 在学kotlin 泛型之前,先回顾一下Java中的泛型为了方便说明引入下面几个类 具体代码 public class Animal { } public class Dog extends Animal{ } public cl

knight康康的博客 2406

Kotlin系列——泛型型变

本文章讲解的内容是泛型的型变,我写一个扩展Boolean的示例代码来应用我要奖的内容,示例代码如下: BooleanExtensionDemo 先看下以下例子,代码如下: List<String> strings = new ArrayList<String>(); // Java中禁止这样的操作 List<Object> objects = strings; ...

qq_20417381的博客 3482

Kotlin泛型学习篇

有时你想说,你对类型参数一无所知,但仍然希望以安全的方式使用它。这里的安全方式是定义泛型类型的这种投影,该泛型类型的每个具体实例化都会是该投影的子类型。仅使用 Kotlin 时,您不太可能需要显式声明绝对不可为 null 的类型,因为 Kotlin 的类型推断会为您处理此问题。这么做毫无意义, 因为我们可以像以前一样在该对象上调用所有相同的方法,所以更复杂的类型并没有带来价值。由于类型擦除,并没有通用的方法在运行时检测一个泛型类型的实例是否通过指定类型参数所创建 ,并且编译器禁止这种。但这样会有一些影响。

子冉冰清的博客 2057

转向Kotlin——泛型

无论是Java还是Kotlin,泛型都是一个非常重要的概念,简单的泛型应用很容易理解,不过也有理解起来麻烦的时候。 泛型基础 在了解Kotlin的泛型之前,先来看看Java中的泛型: 举个栗子:在JDK中,有一类列表对象,这些对象对应的类都实现了List接口。List中可以保存任何对象: List list=new ArrayList(); list.add(55); list.add(&amp;quot;...

jiashuai94的博客 1953

【码上开学】Kotlin 的泛型

List

2401_84408734的博客 1254

Java泛型与Kotlin泛型

正文 本文主要列举Java泛型与Kotlin泛型的基本知识,以及两者的区别。 什么泛型 泛型程序设计是程序设计的一种风格或或规范。简单的说就是该类型可变,在编写代码时可以根据情况设置不同的类型。因为泛型的可变性,很容易出现类型转换异常,Java与Kotlin在编译期间提供了泛型检测,帮助开发者在编译期间就能尽量避免此异常的出现。 Java泛型的基本知识 Java泛型主要用在类,接口,类方法。泛型仅在编译期间有效,编译完成后擦除泛型标记。 // 类 class ObjectA<T>{} // 接口

珠穆朗玛小王子的博客 1136
上一篇: Android MVP之kotlin初体验
下一篇: 动态代理模式原理之反射动态加载技术
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值