Kotlin(2.8)泛型

本文详细介绍了Kotlin中的泛型用法,包括泛型类和泛型函数的定义与使用,对比了Kotlin与Java中泛型的区别,并探讨了泛型的限制条件以及类型预测等内容。

2-知识点汇总

1、如何使用泛型

//类似Java的声明
class Box<T>(t: T) {
    var value = t
}

val box: Box<Int> = Box<Int>(1) //完整形式

val box = Box(1) //可推测出时,可以省略参数类型。

2、和Java区别

  1. Java有通配符(wildcard type),Kotlin没有
  2. Kotlin中有declaration-site variance(声明-位置 变化量)和type projections(类型预测)

3、Java中的泛型

  1. Java中泛型是不变量:List不是List的子类
  2. Java中应该使用泛型限制List<? extends E>,使得List是其子类。
  3. List
fun copy(from: Array<out Any>, to: Array<Any>) {
  // ...
}

表明from不仅是数组,而且是被保护的。

7、使用点变化量:相反于形如Java中Array

fun fill(dest: Array<in String>, value: String) {
    // ...
}

这等于Array<? super Object>,可以传入CharSequence或者object的数组。

8、‘*’星号预测

!!!!!

9、泛型函数
一般泛型函数:泛型在函数名前

fun <T> singletonList(item: T): List<T> {
    // ...
}

扩展函数:T.fun()

fun <T> T.basicToString() : String {  //扩展函数
    // ...
}

10、泛型的限制:Upper bounds

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

T必须为Comparable的子类。

11、需要两个及以上限制:
使用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() }
}
<think> 首先,用户要求我解释Kotlin的详细讲解。参考了提供的引用,我需要基于这些内容构建一个清晰、结构化的回答。 关键点从引用中提取: - 引用[1]:Java和Kotlin的差异。Kotlin要求在实例化类时必须指定具体类,因为Kotlin从一开始就有,不需要向后兼容旧代码。这与Java不同,Java允许不指定类参数。[^1] - 引用[2]:Kotlin的类推导机制,允许在某些情况下省略。[^2] - 引用[3]:逆变的使用,如Comparable<in T>,其中'in'关键字表示逆变,T用作函数的输入。[^3] - 引用[4]:区分'in'和'out'关键字: - 'in'用于逆变:如果A是B的子类,那么Consumer<B>是Consumer<A>的子类参数作为输入。 - 'out'用于协变:如果A是B的子类,那么Producer<A>是Producer<B>的子类参数作为输出。[^4] 用户的问题是基于这些引用,但系统指令说“上述引用仅供参考”,所以我应该确保回答真实可靠,专注于Kotlin的核心概念。 回答结构必须清晰,帮助用户逐步解决问题。系统指令要求使用中文回答,所以所有内容用中文。 大纲一个结构化的回答: 1. **介绍Kotlin中的作用**:解释为什么需要,比如类安全、代码重用。 2. **基本用法**:如何定义和使用类和函数。 - 引用[1]提到Kotlin要求显式声明类或推导。 - 引用[2]展示类推导的例子。 3. **协变和逆变**: - 解释'out'用于协变:生产者(输出)。 - 解释'in'用于逆变:消费者(输入)。 - 引用[3]和[4]提供细节。 4. **不变**:如果没有指定'in'或'out',是不变的。 - 引用[3]提到“不变-无子类化关系”。 5. **差异点与Java**:简要比较Kotlin和Java的实现,如引用[1]所述。 6. **例子**:提供代码示例来阐明概念。 - 使用代码块来演示定义和使用。 - 确保LaTeX语法正确:行内数学用$...$,独立公式用$$...$$。但这个问题主要是代码和描述,可能不需要数学表达式。 7. **常见问题或陷阱**:如类擦除(在JVM上),但Kotlin有更好的支持。 8. **总结**:回顾关键点。 最后,生成相关问题:类似于系统指令中的示例。 确保回答真实可靠:基于标准Kotlin文档和知识。引用提供的引用时,自然地添加引用标识如[^1]。 回答结构: - 开头简要介绍。 - 分节解释核心概念。 - 结束时生成相关问题。 相关问题生成: - 类似于示例,基于内容生成问题。 - 例如: 1. Kotlin中如何使用'in'和'out'来控制协变和逆变? 2. Kotlin与Java的区别是什么? 3.Kotlin中如何处理擦除? 4. 如何定义函数或扩展函数? </think> ### Kotlin的详细讲解 Kotlin 的核心特性之一,它在编译时提供类安全,避免了运行时类转换错误,同时提升了代码的可重用性和可读性。Kotlin设计借鉴了 Java,但做了显著改进以提高严谨性和灵活性。以下我将从基础概念到高级特性逐步讲解,确保内容真实可靠(基于 Kotlin 官方文档和 JVM 规范[^1][^4])。 #### 1. **的基本用法** 允许你在类、接口或函数中定义类参数(如 `T`),在使用时指定具体类Kotlin 要求在使用时必须显式声明类或通过编译器类推导确定类,这避免了 Java 中的向后兼容问题(如未指定的危险实例化)[^1]。 - **定义类**: ```kotlin class Box<T>(val content: T) // T 是类参数 ``` - **使用类推导简化代码**(引用[^2]): ```kotlin val intBox = Box(42) // 编译器推导出 T 为 Int,无需显式指定 val stringBox = Box("Hello") // T 推导为 String ``` 如果推导失败,必须显式声明: ```kotlin val unknownBox: Box<Number> = Box(10) // 显式指定 T 为 Number ``` #### 2. **中的方差控制:协变与逆变** Kotlin 通过 `out` 和 `in` 关键字管理的子类关系,解决类安全与灵活性之间的矛盾。这与 Java 的通配符(`? extends` 和 `? super`)类似,但语法更简洁。 - **`out` 用于协变(Covariance)**(引用[^4]): - 含义:如果 `A` 是 `B` 的子类,则 `Producer<A>` 是 `Producer<B>` 的子类。 - 使用场景:参数只作为输出(生产值),例如只读集合。 - 示例: ```kotlin interface Producer<out T> { fun get(): T // T 只能作为返回值(输出) } ``` 使用示例: ```kotlin val stringProducer: Producer<String> = ... val anyProducer: Producer<Any> = stringProducer // 安全,因为 String 是 Any 的子类 ``` - **`in` 用于逆变(Contravariance)**(引用[^3][^4]): - 含义:如果 `A` 是 `B` 的子类,则 `Consumer<B>` 是 `Consumer<A>` 的子类。 - 使用场景:参数只作为输入(消费值),例如函数参数。 - 示例(如 `Comparable<in T>`): ```kotlin interface Consumer<in T> { fun consume(item: T) // T 只能作为参数(输入) } ``` 使用示例: ```kotlin val anyConsumer: Consumer<Any> = ... val stringConsumer: Consumer<String> = anyConsumer // 安全,因为 Any 能处理 String ``` - **不变(Invariance)**: - 默认情况下,如果不指定 `out` 或 `in`,不具有子类关系(例如 `Box<String>` 和 `Box<Any>` 无继承关系)。 - 示例: ```kotlin val boxString: Box<String> = Box("Kotlin") // val boxAny: Box<Any> = boxString // 编译错误,因为没有子类关系 ``` #### 3. **中的类擦除与实化** - **类擦除**:在 JVM 上,信息在运行时被擦除(与 Java 相同),例如 `List<String>` 和 `List<Int>` 在运行时都是 `List<*>`。 - **实化**(Reified Generics):Kotlin 通过 `inline` 函数和 `reified` 关键字在运行时保留类信息。 ```kotlin inline fun <reified T> checkType(item: Any) { if (item is T) println("Is type T") // 可在运行时检查 T } ``` #### 4. **Kotlin 与 Java 的差异** - **严格类要求**:Kotlin 强制指定,避免 Java 的“原始类”问题(如 `List list = new ArrayList()` 在 Java 允许但危险)[^1]。 - **语法简化**:Kotlin 使用 `out`/`in` 替代 Java 的 `? extends`/`? super`,提高可读性。 - **默认行为**:Kotlin 默认为不变(invariant),而 Java 允许更灵活的协变/逆变使用。 #### 5. **实际应用示例** 定义一个类并演示协变/逆变: ```kotlin class Container<T>(private var item: T) { fun getItem(): T = item // 'getItem' 输出 T,适用协变 fun setItem(newItem: T) { item = newItem } // 'setItem' 输入 T,适用逆变 } // 协变示例 val stringContainer: Container<out String> = Container("Test") val value: Any = stringContainer.getItem() // 安全 // 逆变示例 val anyContainer: Container<in Any> = Container(123) anyContainer.setItem("New Value") // 安全,Any 能处理 String ``` #### 总结 Kotlin通过 `out`(协变)、`in`(逆变)和严格类推导,在编译时确保类安全,同时支持灵活的代码设计。它与 Java 的主要区别在于更严谨的类处理和语法改进[^1][^4]。如果你使用类,记住: - 使用 `out` 当参数只作为输出。 - 使用 `in` 当参数只作为输入。 - 默认情况下优先保持不变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值