Kotlin对比Java 入门学习记录(捌)

Kotlin入门学习记录
2023/12/04 - 2023/12/06

接口

接口默认为open修饰,即为可以继承的,代码实现如下

interface Moveable {
    var maxSpeed:Int
    var wheels:Int
    fun move(moveable: Moveable):String
}
class Car(_name:String,override var wheels:Int = 4):Moveable{
    override var maxSpeed: Int
        get() = TODO("Not yet implemented")
        set(value) {}

    override fun move(moveable: Moveable): String {
        TODO("Not yet implemented")
    }
}

接口的默认实现

可在接口中的属性提供默认的 getter 方法实现,代码实现如下

interface Moveable {
    val maxSpeed:Int
        get() = (0..9).shuffled().first()
        
    var wheels:Int
    fun move(moveable: Moveable):String
}
class Car(_name:String,override var wheels:Int = 4):Moveable{
    override fun move(moveable: Moveable): String {
        TODO("Not yet implemented")
    }

}
fun main() {
    println(Car("LY_C").maxSpeed)
}

抽象类

abstract 关键字,除了具体的函数实现,抽象类也可以包含抽象函数

泛型

泛型系统允许函数和其他类型接受你或编译器当前无法预知的类型

泛型类

泛型类的构造函数可以接受任何类型,<>用于声明一个泛类,<>中可以使用任何字母,不过泛型参数通常用字母T表示,代码实现如下

class MagicBox<T>(item:T){
    private var subject = item
}
class Boy(val name:String,val age:Int)
class Dog(val weight:Int)
fun main() {
    val magicBox:MagicBox<Boy> = MagicBox(Boy("LY_C", 21))
    val magicBox1:MagicBox<Dog> = MagicBox(Dog(20))
}

泛型参数

泛型参数也可以用于函数,代码实现如下

/*
	将Boy对象赋值给MagicBox中的subject属性
	fetch()函数中使用了 takeIf内置函数 
	判断available为false时返回null
	为true时返回subject本身即Boy对象
*/
class MagicBox<T>(item:T){
    var available = false
    private var subject = item
    fun fetch():T?{
        return subject.takeIf { available }
    }
}
class Boy(val name:String,val age:Int)
fun main() {
    val magicBox = MagicBox(Boy("LY_C", 21))
    magicBox.available = true
    magicBox.fetch()?.run {
        println("you find $name")//you find LY_C
    }
}

多泛型参数

泛型函数或泛型类也可以有多个泛型参数,代码实现如下
新 fetch 函数多了一个泛型参数 R。R 是英文单词 return 的缩写形式,表示这个泛型参数将用作 fetch 函数的返回类型

class MagicBox<T>(item:T){
    var available = false
    /*将对象赋值给MagicBox中的subject属性*/
    private var subject = item
    fun fetch():T?{
        return subject.takeIf { available }
    }
    /*定义了一个用于返回的<R> 
    参数为 subjectModFunction:(T) -> R 函数*/
    fun <R> fetch(subjectModFunction:(T) -> R):R?{
    	/*传递subject参数给subjectModFunction*/
        return subjectModFunction(subject).takeIf { available }
    }
}
class Boy(val name:String,val age:Int)
class Man(val name:String,val age:Int)
fun main() {
    val magicBox = MagicBox(Boy("LY_C", 11))
    magicBox.available = true
    val man = magicBox.fetch(){
    	/*相当于subjectModFunction的函数体
    	 接收subject 返回Man对象赋值给<R>*/
        Man(it.name, it.age.plus(10))
    }
    man?.let { println("${it.name},${it.age}") }
}

泛型类型约束

如果只想传递一个类型的泛型,需要在声明泛型的时候给泛型指定类型,代码实现如下

class MagicBox<T:Human>(item:T){
    var available = false
    var subject = item
    fun fetch():T?{
        return subject.takeIf { available }
    }
}
class Boy(val name:String,val age:Int):Human()
open class Human()
fun main() {
    var box = MagicBox(Boy("LY_C", 21))
}

vararg关键字和get运算符函数

使用vararg关键字,能接受多个值参,代码实现如下
注意
可变泛型参数赋值时必须加上out

class MagicBox<T:Human>(vararg item:T){
...
    fun <R> fetch(index: Int,subjectModFunction:(T) -> R) : R? {
        return subjectModFunction(subject[index]).takeIf { available }
    }
}
class Boy(val name:String,val age:Int):Human()
class Gril(val name:String,val age:Int):Human()
open class Human()
fun main() {
    val box = MagicBox(Boy("LY_C", 21),Boy("Test", 21))
    box.available = true
    box.fetch(1)?.run {
        println("you find $name")
        	//you find Test
    }
    box.fetch(0)?.run {
        println("you find $name")
        	//you find LY_C
    }
    val fetch = box.fetch(1) {
        Gril("CRY", 21)
    }
    fetch?.let { println("${it.name},${it.age}") }
    	//CRY,21
}

使用get运算符实现替代第一个fetch函数,代码实现如下

class MagicBox<T:Human>(vararg item:T){
...
    operator fun get(index: Int):T? = subject[index].takeIf { available }
...
}
...
fun main() {
    val box = MagicBox(Boy("LY_C", 21),Boy("Test", 21))
    box.available = true
    box[1]?.run {
        println("you find $name")
        	//you find Test
    }
    box[0]?.run {
        println("you find $name")
       		//you find LY_C
    }
}

in、out 逆变、协变

为进一步定制泛型参数,Kotlin 提供了 inout 两个关键字
子类泛型对象可以赋值给父类用<out >
如果泛型类只将泛型进行返回输出,那么使用out,代码实现如下

interface Production<out T>{
    fun production():T
}
open class Food
open class FastFood:Food()
class Burger:FastFood()
class FoodShore:Production<Food>{
    override fun production(): Food {
        println("Production food")
        return Food()
    }
}
class FastFoodShore:Production<FastFood>{
    override fun production(): FastFood {
        println("Production food")
        return FastFood()
    }
}
fun main() {
	//子类 Burger、FastFood 泛型对象可以
	//赋值给父类 Food 用<out >
    val production:Production<Food> = FoodShore()
    val production2:Production<Food> = FastFoodShore()
    val production3:Production<Food> = BurgerShore()
}

父类泛型对象可以赋值给子类用<in >
如果泛型类只将泛型作为参数传入,那么使用in,代码实现如下

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

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

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

fun main() {
...
	//父类 Food 、FastFood 泛型对象可以
	//赋值给子类 Burger 用<out >
    val everybody:Consumer<Burger> = Everybody()
    val everybody2:Consumer<Burger> = ModernPeople()
    val everybody3:Consumer<Burger> = American()
}

一张图理解协变逆变

invariant 不变

如果泛型类即将泛型作为参数传入又将泛型类作为输出,那么即不使用out又不使用in

reified 关键字

想知道某个泛型参数具体是什么类型。reified 关键字能帮你检查泛型参数类型,代码实现如下

class MagicBox<T:Human>(){
	//randomBackup函数参数写 backup 函数头
    inline fun <reified T> randomBackup(backup:() -> T):T?{
        val item = listOf(
            Boy("test1",21),
            Boy("test2",21)
        )
        val random:Human = item.shuffled().first()
        // is 使用了多态 Boy继承了Human
        // 如果 randomBackup传入的lambda是Boy或者Human 
        // 则返回item列表中随机元素
        // 否则返回 randomBackup中的lambda值
        return if (random is T){
            random
        }else{
            backup()
        }
    }
}
class Boy(
	override val name:String,
	override val age:Int
):Human(name, age)
class Gril(val name:String,val age:Int)
class Man(
	override val name:String, 
	override val age:Int
):Human(name, age)
open class Human(
	open val name:String, open val age:Int)
fun main() {
    var box:MagicBox<Man> = MagicBox()
    val subject = box.randomBackup {
    	// 传入lambda
        Man("LY_C",21)
        Gril("CRY",21)
        Human("LY_C",21)
    }
    println(subject?.name)
}
  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuKey_C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值