一、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)