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

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

一、Kotlin中接口的定义

  • Kotlin中接口定义
    Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中
    定义的函数并不需要open关键字修饰,它们默认就是open的。
/**
 * Kotlin中接口定义
 * Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中
 * 定义的函数并不需要open关键字修饰,它们默认就是open的。
 */
interface Movable {
    /**
     * 默认实现
     * 只要你愿意,你可以在接口里提供默认属性的getter方法和函数实现。
     */
    val maxSpeed: Int
        get() = (1..500).shuffled().last()
    var wheels: Int
    fun move(movable: Movable): String
}
class Car(_name: String, override var wheels: Int = 4) : Movable {
    override var maxSpeed: Int
        get() = super.maxSpeed
        set(max) {
        }
    override fun move(movable: Movable): String {
        println("数据一下")
        return "数据一下"
    }
}

二、抽象类

/**
 * 抽象类
 * 要定义一个抽象类,你需要在定义之前加上abstract关键字,除了具体的函数实现,
 * 抽象类也可以包含抽象函数(只有定义,没有函数实现)
 */
abstract class Gun(val range: Int) {
    abstract fun pullTrigger(): String
    protected fun doSomething() {
        println("doSomething")
    }
}
class AK47(val price: Int) : Gun(range = 500) {
    override fun pullTrigger(): String {
        return "ce"
    }
}

三、泛型详解

/**
 * 定义泛型类
 * 泛型类的构造函数可以接受任何类型。
 * MagicBox类指定的泛型参数由放在一对<>里的字母T表示,T是个代表item类型的占位图。
 * MagicBox类接受任何类型的item作为主构造函数值(item:T),并将item赋值给同样是T类型的
 * subject私有属性
 *
 * 泛型参数通常用字母T(代表type)表示,当然,想用其他字母,甚至是英文单词都是可以的。
 * 不过,其他支持泛型的语言都在用这个约定俗称的T,所以建议你继续用它,这样写出的代码别人更容易理解。
 *
 * 泛型类型约束
 * 如果要确保MagicBox里面只能装指定类型的物品,如Human类型,或其子类 这样定义<H : Human>
 */
class MagicBox<T : Human>(vararg item: T) {
    var available = false
    private var subject: Array<out T> = item
    /**
     * 泛型函数
     * 泛型参数也可用于函数
     * 定义一个函数用于获取元素,当且仅当MagicBox可用时,才能获取元素。
     */
    fun fetch(index: Int): T? {
        return subject[index].takeIf {
            available
        }
    }
    /**
     *
     * 多泛型参数
     * 泛型函数或泛型类也可以有多个泛型参数
     *
     * 把元素进行修改
     * 魔盒里面放的是男孩,取出来的时候,改成男人
     */
    fun <R> fetch(index: Int, subjectModFunction: (T) -> R): R? {
        return subjectModFunction(subject[index]).takeIf {
            available
        }
    }
}
open class Human(val age: Int)
class Boy(val name: String, age: Int) : Human(age)
class Dog(val weight: Int)
class Man(val name: String, age: Int) : Human(age)
fun main() {
    val magicBox = MagicBox(
        Boy("jack", 15),
        Boy("Jacky", 16),
        Boy("John", 26)
    )
    magicBox.available = true
    magicBox.fetch(1)?.run {
        println("you find $name")
    }
    val man = magicBox.fetch(2) {
        Man(it.name, it.age + 10)
    }
}

输出结果如下

you find Jacky

四、out协变和in逆变详解

/**
 * out 协变,如果泛型类只将泛型类型作为函数的返回(输出),那么使用out
 * 可以称之为生产类/接口,因为它主要用来生产(produce)指定的泛型对象。
 *
 * 子类泛型对象可以赋值给父类泛型对象,用out
 */
interface Production<out T> {
    fun product(): T
}
/**
 * in 逆变
 *in(逆变),如果泛型类只将泛型类型作为函数的入参(输入),那么使用in,可以称之为消费者类/接口,
 * 因为它主要用来消费(consumer)指定的泛型对象
 *
 *  父类泛型对象可以赋值给子类泛型对象,用in
 *
 */
interface Consumer<in T> {
    fun consumer(item: T)
}
/**
 * invariant(不变)
 * 如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么既不用out也不用in
 */
interface ProductionConsumer<T> {
    fun product(): T
    fun consume(item: T)
}
open class Food
open class FastFood : Food()
class Burger : FastFood()
/**
 * 食品商店
 */
class FoodStore : Production<Food> {
    override fun product(): Food {
        println("Product food.")
        return Food()
    }
}
/**
 * 快餐商店
 */
class FastFoodStore : Production<FastFood> {
    override fun product(): FastFood {
        println("Product food.")
        return FastFood()
    }
}
/**
 * 汉堡商店
 */
class BurgerStore : Production<Burger> {
    override fun product(): Burger {
        println("Product food.")
        return Burger()
    }
}
fun main() {
    //赋值
    val production1: Production<Food> = FoodStore()
    val production2: Production<Food> = FastFoodStore()
}

五、reified关键字

/**
 * @Author: ly
 * @Date: 2023/2/1
 * @Description:
 */
class MagicBox<T : Human> {
    /**
     * 随机产生一个对象,如果不是指定类型的对象,
     * 就通过backup函数生成一个指定类型的对象
     */
//    fun <T> randomOrBackup(backup: () -> T): T {
//        val items = listOf(
//            Boy("Jack", 20),
//            Man("John", 35)
//        )
//        var random = items.shuffled().first()
//        return if (random is T) {
//            random
//        } else {
//            backup()
//        }
//    }
    /**
     * reified关键字
     * 有时候,你可能想知道某个泛型参数具体是什么类型,reified关键字能够帮你
     * 检查泛型参数类型。Kotlin不允许对泛型类型T做类型检查,因为泛型参数类型会被类型擦除
     * 也就是说,T的类型信息在运行时是不可知的,Java也有这样的规则。
     * */
    inline fun <reified T> randomOrBackup(backup: () -> T): T {
        val items = listOf(
            Boy("Jack", 20),
            Man("John", 35)
        )
        val random = items.shuffled().first()
        return if (random is T) {
            println(random)
            random
        } else {
            backup()
        }
    }
}
open class Human(val age: Int)
class Boy(val name: String, age: Int) : Human(age) {
    override fun toString(): String {
        return "Boy(name='$name',age=$age)"
    }
}
class Man(val name: String, age: Int) : Human(age) {
    override fun toString(): String {
        return "Man(name='$name',age=$age)"
    }
}
fun main() {
    val box1: MagicBox<Boy> = MagicBox()
    //由backup函数,推断出来T的类型
    val subject = box1.randomOrBackup {
        Boy("Jack", 19)
    }
    println(subject)
}

输出结果

Boy(name='Jack',age=19)
另外一种可能输出的结果
Boy(name='Jack',age=20)
Boy(name='Jack',age=20)


目录
相关文章
|
4月前
|
安全 Java Kotlin
Kotlin泛型:灵活的类型参数化
Kotlin泛型:灵活的类型参数化
|
Java API 调度
Kotlin 中的suspend 关键字
Kotlin 中的suspend 关键字
178 0
|
4月前
|
安全 Kotlin 容器
Kotlin 中的协变与逆变
Kotlin 中的协变与逆变
221 1
|
3月前
|
SQL 安全 Java
Android经典面试题之Kotlin中object关键字实现的是什么类型的单例模式?原理是什么?怎么实现双重检验锁单例模式?
Kotlin 单例模式概览 在 Kotlin 中,`object` 关键字轻松实现单例,提供线程安全的“饿汉式”单例。例如: 要延迟初始化,可使用 `companion object` 和 `lazy` 委托: 对于参数化的线程安全单例,结合 `@Volatile` 和 `synchronized`
46 6
|
4月前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
35 3
Android面试题之Java 泛型和Kotlin泛型
|
4月前
|
Kotlin
Kotlin中抽象类与接口
Kotlin中抽象类与接口
Android-kotlin-接口与多态的表现,面经解析
Android-kotlin-接口与多态的表现,面经解析
|
API Kotlin
Kotlin中扩展函数、infix关键字、apply函数和DSL的详解
Kotlin中扩展函数、infix关键字、apply函数和DSL的详解
115 0
|
Kotlin
Kotlin中继承、类型转换、Any超类、object关键字详解
Kotlin中继承、类型转换、Any超类、object关键字详解
134 0
|
Kotlin
Kotlin 中定义类、field关键字,主构造函数和次构造函数详解
Kotlin 中定义类、field关键字,主构造函数和次构造函数详解
154 0