一起学Kotlin(8)_接口、抽象类、泛型

接口、抽象类、泛型,这些在Java中我们都是常见且经常使用的,相信大家都不会陌生了。这里我们就看下它们的异同吧。
一 接口
Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数并不需要open关键字修饰,他们默认就是open的。
1.1 接口的定义及实现

interface Movable{
    val maxSpeed:Int
    var wheels:Int
    fun move(movable: Movable):String
}
class Car(_name:String,override var wheels:Int = 4):Movable{
    var name = _name
    override val maxSpeed: Int
        get() = 100

    override fun move(movable: Movable): String {
        return "$name max speed is ${movable.maxSpeed},has ${movable.wheels} wheels"
    }
}
val car = Car("BMW",8)
println(car.move(car))
//结果
BMW max speed is 100,has 8 wheels

1.2 接口默认实现

interface Movable{
    val maxSpeed:Int
        get() = (1..500).shuffled().last()
    var wheels:Int
    fun move(movable:Movable):String
}
class Car(var name:String,override var wheels:Int = 4):Movable{
    override val maxSpeed: Int
        get() = super.maxSpeed

    override fun move(movable: Movable): String {
        return "$name has $wheels wheel,max speed is ${movable.maxSpeed}"
    }
}

这里的默认实现只是在接口里默认实现了属性取值,然后实现类可以直接取父接口的属性值。总体来看Kotlin的接口使用与Java差异不太大。

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

abstract class Gun(val range:Int){
    abstract fun trigger():String
}
class AK47(val price:Int,range:Int):Gun(range = range){
    override fun trigger(): String {
        return "AK47 price is $price,shooting $range"
    }
}
val aK47 = AK47(9999,108)
println(aK47.trigger())
//结果
AK47 price is 9999,shooting 108

感觉没什么好多解释的了,除了一些写法不一样,其余与Java基本一致,看代码理解下就可以了。

三 泛型
泛型通常用字母T(Type)表示,要是想用其它字母甚至是英文单词都是可以的。不过在其它支持泛型的语言通常都使用T,慢慢的成了一个约定俗成。为了让别人更容易理解你的代码,也建议使用T。
3.1 定义泛型类
泛型类的构造函数可以接受任何类型

class MagicBox<T>(item:T){
    var subject:T = item
}
data class Boy(val name:String,val age:Int)
data class Dog(val weight:Int)
val box0 = MagicBox(Boy("Jack",18))
val box1 = MagicBox(Dog(20))

3.2 泛型函数
在上面例子的基础上我们将磨合改一改

class MagicBox1<T>(item:T){
    var availavle = true
    private var subject:T = item
    fun fetch():T?{
        return subject.takeIf { availavle }
    }
}
val box0 = MagicBox1(Boy("Jack",18)).fetch()
val box1 = MagicBox1(Dog(20)).fetch()
println(box0.toString())
println(box1.toString())
//结果
Boy(name=Jack, age=18)
Dog(weight=20)

嘿嘿,是不是感觉很奇怪,明明直接实例化就好了,还搞得那么麻烦。其实这样写也是有其好处的,可以方便统一实例化工作的管理,在Android源码里就使用了很多这样的构建方式,也是一种构建思想了。当然,它是用Java写的而已。

3.3 多泛型参数
泛型函数或泛型类也可以有多个泛型参数。感觉很绕,无法理解。那么我们通俗点,比如我们开始传入的是一个男孩,然后最后我们需要得到一个男人怎么处理?这个要是你玩过RxJava的话,应该是处理过类似的需求的。

class MagicBox2<T>(item:T){
    var availavle = true
    private var subject:T = item
    fun fetch():T?{
        return subject.takeIf { availavle }
    }
    fun <R>fetch(subjectModFunction:(T)->R):R?{
        return subjectModFunction(subject).takeIf { availavle }
    }
}
data class Man(val name:String,val age:Int)
val box2 = MagicBox2(Boy("Jack",18)).fetch{
        Man(it.name,it.age.plus(10))
    }
println(box2.toString())
//结果
Man(name=Jack, age=28)

在变换的过程中一定有函数的介入处理的,但事先我们并不知道它的具体类型,所以有了T、R两个泛型,然后通过外部传入lambda表达式来进行了转换。这种处理方式在实际项目中是会经常用到的。
3.4 泛型约束
如果要确保我们的泛型只能是某种类型的泛型该怎么处理呢?那么我们需要对我们的泛型进行条件约束。

class MagicBox3<T:Man>(item:T){
    var availavle = true
    private var subject:T = item
    fun fetch():T?{
        return subject.takeIf { availavle }
    }
}
//这个是非法的,不符合约束条件
//val box3 = MagicBox3(Boy("Jack",18))
 //这句代码就没问题了
val box4 = MagicBox3(Man("Jack",18))

其实类似的用法我们在Java中也应该写过,就是对泛型进行约束,要求只能是某种类型的子类。Java的写法是 T extend Man 这种写法而已。

3.5 可变参数泛型
我们设计的程序一次只能放入一个,但如果我一次想放入N个,但又可能不确定,那这时候我们的可变参数就派上用场了。可变参数使用vararg关键字。

class MagicBox4<T>(vararg item:T){
    var availavle = true
    private var subject:Array<out T> = item
    fun fetch(index:Int):T?{
        return subject[index].takeIf { availavle }
    }
}
val box5 = MagicBox4(Boy("Jack",18),Dog(20),Man("Jacky",30))
println(box5.fetch(1))
//结果
Dog(weight=20)

这里需要注意的点:1、需要使用vararg关键字指明参数为可变参数 2、subject接收的类型变为了Array,且类型需要使用out进行修饰(out in在下节在说) 3、取值的时候需要下标做取值索引

3.6 []取值操作符
在上面的代码中,如果我们想通过box5[1]这种方式进行取值是行不通的。但我们可以通过重载运算符函数get来实现此功能。

class MagicBox4<T>(vararg item:T){
    var availavle = true
    private var subject:Array<out T> = item
    fun fetch(index:Int):T?{
        return subject[index].takeIf { availavle }
    }
    operator fun get(index: Int):T? = subject[index].takeIf { availavle }
}

通过重载get运算符函数,我们就可以通过[]直接取值了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值