MST

星途 面试题库

面试题:Kotlin泛型约束及协变逆变的复杂应用

假设有一个电商系统,有`Product`类作为所有商品的基类,`Book`和`Clothes`继承自`Product`。设计一个`Cart`类,要求能够支持不同类型商品的添加,但要保证类型安全,并且要利用协变和逆变优化商品在不同场景下的传递和使用,写出相关的Kotlin代码并解释设计思路。
49.7万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试
// 定义商品基类
open class Product(val name: String)

// 书籍类,继承自Product
class Book(name: String, val author: String) : Product(name)

// 服装类,继承自Product
class Clothes(name: String, val size: String) : Product(name)

// 使用out关键字实现协变,用于只读场景
class Cart<out T : Product> {
    private val items: MutableList<T> = mutableListOf()

    // 添加商品到购物车
    fun addItem(item: T) {
        items.add(item)
    }

    // 获取购物车中的商品列表
    fun getItems(): List<T> {
        return items
    }
}

// 示例使用
fun main() {
    val bookCart: Cart<Book> = Cart()
    bookCart.addItem(Book("Effective Kotlin", "Marina Samsonova"))

    val productCart: Cart<Product> = bookCart
    val products: List<Product> = productCart.getItems()
    products.forEach { println(it.name) }
}

设计思路解释

  1. 基类和子类定义:定义了Product作为所有商品的基类,BookClothes继承自Product,这样不同类型的商品就有了共同的基类,方便进行统一管理。
  2. Cart类设计Cart类使用了泛型<out T : Product>,这里的out关键字实现了协变。协变意味着Cart<Book>类型的对象可以安全地赋值给Cart<Product>类型的变量,因为Cart类中只对T进行读取操作(如getItems方法返回List<T>),而没有写入操作(如果有写入操作,就可能破坏类型安全)。
  3. 类型安全与协变逆变应用:通过协变,保证了不同类型商品(如BookClothes)在Cart中的添加和获取是类型安全的,同时利用协变优化了商品在不同场景下的传递和使用,比如可以将Cart<Book>传递给期望Cart<Product>的地方,因为BookProduct的子类型,符合协变规则。在这个例子中,购物车主要是对商品进行添加和读取,所以协变满足其设计需求。如果有需要在购物车中进行更多复杂操作(如替换商品等),可能会涉及到逆变等更复杂的类型处理,但在本题需求下,协变足以满足类型安全和优化传递使用的要求。