Android---Kotlin 学习010

接口

接口定义

Kotlin 规定所有的接口属性和函数实现都要使用 override 关键字,接口中定义的函数并不需要 open 关键字修饰,他们默认就是 open 的。

示例:

接口的默认实现

只要愿意,你可以在接口里提供默认属性的 get() 方法和函数实现。

注意:我们在接口里定义属性的情况不是很多。接口里面一般只提供功能函数的声明。

 抽象类

要定义一个抽象类,你需要在定义之前加上 abstract 关键字,除了具体的函数实现,抽象类也可以包含抽象函数---只有定义,没有函数实现。

注意:抽象类里既可以有实现了的函数,也可以有没实现的函数;接口里只能有没实现的函数

泛型类

泛型类的构造函数可以接受任何类型。

MagicBox 类指定的泛型参数放在一对<>里的字母 T 表示,T 是个代表 item 类型的占位符。MagicBox 类接受任何类型的 item 作为主构造函数值(item : T),并将 item 值赋给同样是 T 类型的 subject 私有属性。

注意:泛型参数通常用字母 T(代表英文 type)表示。当然,想用其他字母,甚至是英文单词都是可以的。不过,其它支持泛型的语言都在用这个约定俗成的 T,所以建议你继续用它,这样写出的代码别人更容易理解。

泛型函数

泛型参数也可以用于函数。

定义一个函数用于获取元素,当且仅当 MagicBox 可用时,才能获取元素。即上面代码设置 available 为 true。因为在 fetch() 方法中,takeIf{} 里面的表达式为 true 时,takeIf 返回接收者对象,即这里的泛型类型 magicBoy。

多泛型参数

泛型函数或泛型类也可以有多个泛型参数。

class MagicBox<T>(item : T){
    var available : Boolean = false
    private val subject : T = item

    // 泛型函数
    fun fetch() : T? {
        return subject.takeIf { available }
    }

    // return --> R。TODO 多泛型参数
    // 业务,把元素进行修改。魔盒里面放的是男孩,取出来时,给他改成一个男人
    fun <R> fetch(subjectModFunction : (T) -> R) : R?{
        return subjectModFunction(subject).takeIf { available }
    }
}

class Boy(val name : String, val age : Int)
class Man(val name : String, val age : Int)
class Dog(val weight : Int)

fun main() {
    val magicBoy : MagicBox<Boy> = MagicBox(Boy("jack", 17))
    val magicDog : MagicBox<Dog> = MagicBox(Dog(10))

    magicBoy.available = true
    magicBoy.fetch()?.run {
        println("you find $name")
    }
    // 得到一个 man
    val man : Man? = magicBoy.fetch {
        Man(it.name, it.age.plus(15))
    }
}

泛型类型约束

如果要确保 MagicBox 里面只能装指定类型的物品,比如 Human 类型,怎么办?

 vararg 关键字

MagicBox 能存放任何类型的 Human 实例,但一次只能放一个 T 类型实例。如果需要放入多个 T 类型实例,那么就需要使用到 vararg 关键字

out-协变

out(协变),如果泛型类只将泛型类型作为函数的返回(输出),那么使用 out,可以称之为生产类/接口,因为它主要是用来生产(produce)指定的泛型对象。

示例:

// 生成者
interface Production<out T>{
    //TODO 泛型类型 仅作为 函数的返回 --> 用 out
    fun product() : T
}

open class Food()
open class FastFood() : Food()
class Burger() : FastFood()

class FoodStore() : Production<Food>{
    override fun product(): Food {
        println("Food Store!")
        return Food()
    }
}

class FastFoodStore() : Production<FastFood>{
    override fun product(): FastFood {
        println("Fast Food Store!")
        return FastFood()
    }
}

class BurgerStore() : Production<Burger>{
    override fun product(): Burger {
        println("Burger Store!")
        return  Burger()
    }

}

fun main() {
    val foodStore : Production<Food> = FoodStore()

    /**
     * FastFoodStore() 本来就是继承自 Production<FastFood>,而这里的接收对象为fastFoodStore2的类型Production<Food>
     *     FastFood 是 Food 的子类
     * 这种情况在 Java 里是 子类泛型对象 不能赋值给 父类泛型对象
     * 但是在 kotlin 里,因为有 out 所以就可以这样做
     */
    val fastFoodStore1 : Production<FastFood> = FastFoodStore()
    val fastFoodStore2 : Production<Food> = FastFoodStore()
}

in-逆变

in(逆变),如果泛型类只将泛型类型作为函数的入参(输入),那么使用 in,可以称之为消费者类/接口 ,因为它主要是用来消费(consume)指定的泛型对象。

// 消费者
interface Consumer<in T>{
    //TODO 泛型类型 仅作为 函数的入参 --> 用 in
    fun consume(item : T)
}

open class Food()
open class FastFood() : Food()
class Burger() : FastFood()

class Everybody : Consumer<Food>{
    override fun consume(item: Food) {
        println("Eat food $item")
    }
}

class ModernPeople : Consumer<FastFood>{
    override fun consume(item: FastFood) {
        println("Eat fastFood $item")
    }
}

class American : Consumer<Burger>{
    override fun consume(item: Burger) {
        println("Eat Burger $item")
    }
}

fun main() {
    val everybody1 : Consumer<Food> = Everybody() // 正常情况

    //TODO in : 父类泛型 对象赋值给 子类泛型对象
    val everybody2 : Consumer<FastFood> = Everybody()

    val everybody3 : Consumer<Burger> = Everybody()
    val modernPeople : Consumer<Burger> = ModernPeople()
    val american : Consumer<Burger> = American()
}

invariant-不变

如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么即不用 out 也不用 in。

什么时候使用 in 和 out

1. 父类泛型对象可以赋值给子类泛型对象,用 in。

2. 子类泛型对象可以赋值给父类泛型对象,用 out。

reifield

有时候,你可能想知道某个泛型参数具体是什么类型,reified 关键字能帮你检查泛型参数类型。Kotlin 不允许对泛型参数 T 做类型检查,因为泛型参数类型会被类型擦除,也就是说,T 的类型信息在运行时是不可知的,Java 也有这样的规则。

猜你喜欢

转载自blog.csdn.net/qq_44950283/article/details/135045376