kotlin基础学习-6(接口,泛型相关)

2022-04-23  本文已影响0人  ftd黑马
interface Moveable{
    //接口的定义,kotlin规定所有的接口属性和函数实现都要使用override关键字(也就是任何类实现该接口,必须实现里面的属性和函数实现),接口中定义的函数并不需要open关键字修饰,他们默认就是open的
    //一般接口中不定义属性,只声明一些函数
    val maxSpeed : Int
        get() = (1..50).shuffled().last()
    val wheels : Int

    fun move(moveable: Moveable) : String
}

//接口的定义
class Car(val _name: Int, override val wheels: Int = 4) : Moveable{
    override var maxSpeed: Int
        get() = super.maxSpeed // 这里写法和java一样
        set(value){}
    
    override fun move(moveable: Moveable): String {
        TODO("Not yet implemented")
    }
}
//抽象类
abstract class Gun(val range : Int){
    abstract fun shoot() : String
}
class AK47 : Gun(range = 100){
    override fun shoot(): String {
        return "ak47 shootting......"
    }
}
//定义泛型类
class MagicBox <T : Human> (item : T){
    var available = false
    private val subject : T = item
    //泛型函数也可以用于参数
    fun fetch() : T? {
        //标准函数,当takeif的lambda结果是true,才会返回调用者。如果lambda结果是false,返回null
        return subject.takeIf { available }
    }
    //多泛型参数(1个新需求,要求此函数将一个男孩变成男人)
    //这个重载函数参数是一个匿名函数,匿名函数中的参数是一个T对象,返回的是一个R对象;当前函数返回的就是一个R对象
    fun <R>fetch(subjectModFunction : (T) -> R) : R? {
        return subjectModFunction(subject).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,val age: Int)'

fun main() {
//定义泛型类
    val magicBoy : MagicBox<Boy> = MagicBox<Boy> (Boy("jack",20))

    //如果定义了泛型类型约束,Dog没有继承Human,因此这里不能用了
//    val magicDog  = MagicBox<Dog> (Dog(10))

    //泛型函数
    magicBoy.available = true
    magicBoy.fetch()?.run {
        println("you find $name")
    }

    //多泛型参数
    val man = magicBoy.fetch {
        //返回一个man对象,加了10岁
        Man(it.name, it.age.plus(10))
    }

    println(man?.age)

    //泛型类型约束,类似与java的泛型类型约束
}
package com.example.myapplication

/**
 * varage关键字
 * 需求:magicbox2能存放任何类型的human实例,但是一次只能放一个,如果需要放入多个实例呢
 */

//定义泛型类,这里使用varagr修饰,则这个参数变为可变参数
class MagicBox2 <T : Human> (vararg item : T){

    var available = false

    //这里先暂且记住要写out,不写out会报错
    private val subject : Array<out T> = item

    //泛型函数也可以用于参数
    fun fetch(index : Int) : T? {
        //标准函数,当takeif的lambda结果是true,才会返回调用者。如果lambda结果是false,返回null
        return subject[index].takeIf { available }
    }

    //多泛型参数(1个新需求,要求此函数将一个男孩变成男人)
    //这个重载函数参数是一个匿名函数,匿名函数中的参数是一个T对象,返回的是一个R对象;当前函数返回的就是一个R对象
    fun <R>fetch(index: Int,subjectModFunction : (T) -> R) : R? {
        return subjectModFunction(subject[index]).takeIf { available }
    }

    //[]操作符重载
    operator fun get(index: Int) : T? = subject[index]?.takeIf { available }

}

//泛型类型约束
open class Human2(val age: Int)

class Boy2(val name :String,age : Int) : Human(age)
class Dog2(val weight : Int)

class Man2(val name: String,val age: Int)

fun main() {
    //因为用了varage修饰,这里传参可以传多个
    val magicBoy : MagicBox2<Boy> = MagicBox2<Boy> (Boy("jack",20),Boy("jacky",30))

    magicBoy.available = true

    magicBoy.fetch(1)?.run {
        println("you find $name")
    }

    val man = magicBoy.fetch(1) {
        Man2(it.name,it.age+10)
    }

    println(man?.age)
    
    //[]操作符重载,重载后可以这样调用
    println(magicBoy[1])
}
package com.example.myapplication

/**
 * in 和 out的区别
 */

//out,协变,如果泛型类只将泛型类型作为函数的返回,那么使用out,可以称之为生产类/接口,因为它主要是生产(produce)指定的泛型对象
interface Production<out T>{
    fun product() : T
}

//in,逆变,如果泛型类只将泛型类型作为函数的入参,那么使用in,可以称之为消费者类/接口,因为它主要是用来消费(consume)指定的泛型对象
interface Consumer<in T>{
    fun consumer(item : T)
}

open class Food

open class FastFood : Food()

class Hamburger : FastFood()


//实体商店,生产food(爷爷)
class FoodStore : Production<Food>{
    override fun product(): Food {
        println("food is readey")
        return Food()
    }
}
//快餐商店,生产快餐(爸爸)
class FastFoodStore : Production<FastFood>{
    override fun product(): FastFood {
        println("fastfood is readey")
        return FastFood()
    }
}
//汉堡包商店,生产汉堡包(儿子)
class HamburgerStore : Production<Hamburger>{
    override fun product(): Hamburger {
        println("Hamburger is readey")
        return Hamburger()
    }
}

//----------------以上是生产者demo,out修饰--------------------------------------------
//----------------以下是消费者demo,in修饰---------------------------------------------

class EveryBody : Consumer<Food>{
    override fun consumer(item: Food) {
        println("任何人吃食物")
    }
}

class ModernPeople : Consumer<FastFood>{
    override fun consumer(item: FastFood) {
        println("现代人吃快餐")
    }
}

class American : Consumer<Hamburger>{
    override fun consumer(item: Hamburger) {
        println("美国人吃汉堡")
    }
}


fun main() {
    val food : Production<Food> = FoodStore()
    //下面这两行如果Production没有out关键词修饰,下面是报错的。java中的泛型,左右两边的泛型必须是同一类型,不可以是继承关系的那种。
    //但是在kotlin中,out修饰后,子类泛型对象可以赋值给父类泛型对象
    val fastFood : Production<Food> = FastFoodStore()
    val hamburger : Production<Food> = HamburgerStore()
    hamburger.product()

//----------------以上是生产者demo,out修饰--------------------------------------------
//----------------以下是消费者demo,in修饰---------------------------------------------


    val consumerHamburger : Consumer<Hamburger> = American()
    //下面这两行如果Consumer没有in关键词修饰,下面是报错的。java中的泛型,左右两边的泛型必须是同一类型,不可以是继承关系的那种。
    //但是在kotlin中,in修饰后,父类泛型对象可以赋值给子类泛型对象
    val consumerFood : Consumer<Hamburger> = EveryBody()
    val consumerFastFood : Consumer<Hamburger> = ModernPeople()
}
package com.example.myapplication

/**
 * reified
 * 有时候,可能想知道某个泛型参数具体是什么类型,reified关键字能帮我们检查泛型参数类型,
 */
fun main() {
    val magicBox3 = MagicBox3()
    val randomOrBackUp = magicBox3.getRandomOrBackUp {
        Man3("Tom", 33)
    }
    println(randomOrBackUp)
}


class MagicBox3{
    //这里需要使用reified关键字修饰T,否则下面的retrun里的random is T这一行会报错;
    //添加了reified关键字修饰后,需要将该函数声明为inline内联函数
    inline fun <reified T> getRandomOrBackUp(backup : () -> T) : T{
        val items = listOf(
            Boy3("jack",10),
            Man3("John",30)
        )

        //随机获取到集合的一个对象
        val random = items.shuffled().first()

        println("random       "+random)

        //如果随机获取到的就是T类型,那么直接返回,否则返回backup函数的返回对象
        //Important:这里可能会有疑问,T本身就是泛型,random is T根本看不懂,我理解的是这个T类型本身是什么类型取决与backup函数返回的类型,它返回什么类型,那么整个类里面所有的T泛型都是什么类型
        //这里需要使用关键词reified,否则会报错


        //因为在main方法中调用getRandomOrBackUp传入的匿名函数的返回值是Man3,所以这里的T指的就是Man3
        return if (random is T){
            random
        }else{
            backup()
        }
    }
}

open class Human3(val age: Int)

class Boy3(val name :String,age : Int) : Human3(age){
    override fun toString(): String {
        return "Boy3(name = $name,age = $age )"
    }
}

class Man3(val name: String,age: Int) : Human3(age){
    override fun toString(): String {
        return "Man3(name = $name,age = $age )"
    }
}
上一篇 下一篇

猜你喜欢

热点阅读