Kotlin接口

本文详细介绍了Kotlin中的抽象类和接口的区别与用法。抽象类作为基类,包含抽象方法和属性,而接口则是一个完全抽象的类,用于定义行为规范。在Kotlin中,接口可以有默认实现,类可以实现多个接口,同时解决覆盖冲突。此外,还探讨了函数式接口(SAM)的概念以及类型别名的使用。
摘要由CSDN通过智能技术生成

抽象类

Kotlin抽象类与普通类的主要区别是类内有抽象方法或者抽象属性,而抽象方法不能有方法体

抽象类是对几个具有相似点的类进行抽象成一个基类,这个类就叫做抽象类。抽象类的存在更方便于多态的应用

抽象类可以简单地理解为一个地基,子类可以在这个地基上建造不同特色的建筑

类内有抽象方法 abstract fun 或者有抽象属性 abstract var/val 则需在类声明class前加abstract 

abstract class People(var name:String,var age:Int,var sex:String){
    fun eat(meal:String){
        println(name+"eat $meal")
    }
    fun drink(meal: String){
        println(name+"eat $meal")
    }
    abstract fun doWork()//有{}会报错
}
class Employee(name:String,age: Int,sex: String,var salary:Double)
    :People(name,age,sex){
    override fun doWork() {
        print("This is $name. ")
        when(sex){
            "male"->{
                println("He is an employee. His salary is $salary")
            }
            "female"->{
                println("She is an employee. Her salary is $salary")
            }
        }
    }
}
class Employer(name:String,age: Int,sex: String,var salary: Double)
    :People(name,age,sex){
    override fun doWork() {
        print("This is $name. ")
        when(sex){
            "male"->{
                println("He is an employer. His salary is $salary")
            }
            "female"->{
                println("She is an employer. Her salary is $salary")
            }
        }
    }
}
fun main(args:Array<String>){
    val array:Array<People> = arrayOf(Employee("Hellen",25,"male",54000.5),
                                    Employer("Alice",26,"female",100000.0))
    for (x in array){
        x.doWork()
    }
}
//    运行结果    
//    This is Hellen. He is an employee. His salary is 54000.5
//    This is Alice. She is an employer. Her salary is 100000.0

定义与实现接口

定义接口

接口是一个完全抽象的类,接口默认可继承,接口内的方法也均可重写

接口内的方法可以有方法体接口内没有方法体的方法默认抽象

接口内可以有属性,但属性不能有幕后字段属性也不能被=赋值,可以设置自定义的get set

接口无构造器

接口的定义通过关键字 interface,定义格式为 interface 接口名 { }

interface A{
//    var s=3 //Property initializers are not allowed in interfaces
//    var s:Int
//        get() {return 1}
//        set(value){field=value} //Property in an interface cannot have a backing field
    var name:String //可以允许只声明,此时是抽象属性
    var s: Int
        get() {return 1}
        set(value){value}
    fun a(){
        println("hello ")
    }
    fun b()
}

接口中的属性

在接口中声明的属性要么是抽象的(只声明读写性+变量名+类型),要么提供访问器的实现。在接口中声明的属性不能有幕后字段(backing field)field(set中不能用field),声明的属性也不允许=赋值。

实现接口

实现接口与继承类的方法类似,是在类的主构造函数后 : 接口名 即可

实现接口需要重写接口内的抽象方法和抽象属性

interface A{
   var name:String //抽象属性需要重写
   val name_size:Int //已有get,不用重写
        get()=name.length
   fun sayName(){
       println("This is $name")
   } //已有方法体,不用重写
   fun doWork() //无返回值的抽象方法
}
class Example(override var name: String):A{
    override fun doWork(){
        println("This is $name abstract function")
    }
    //剩下的name_size,sayName 可以重写也可以不用
}
fun main(args:Array<String>){
    val example=Example("Peter")
    println(example.name_size)
    example.sayName()
    example.doWork()
}
// 运行结果
//5
//This is Peter
//This is Peter abstract function

解决覆盖冲突

当类实现多个接口,而多个接口内有同名方法时,则无论接口有没有实现该方法,类都需要重写该方法(类似类的继承的覆盖冲突)

interface A{
    fun sayHello(){
        println("Hello")
    }
}
interface B{
    fun sayHello()
}
class C:A,B{
    //Class 'C' must override public open fun sayHello(): Unit defined in kotlin_learn.A 
    // because it inherits multiple interface methods of it
    override fun sayHello() {
        super<A>.sayHello()
    }
}

接口的继承

一个接口可以从其他接口派生,从而既提供基类型成员的实现也声明新的函数与属性。

接口的继承是可以继承多个的

interface A{
    fun sayHello(){
        println("Hello")
    }
}
interface B{
    fun saHello()
}
interface C:A,B{

}
class D:C{
    override fun saHello() {
        TODO("Not yet implemented")
    }
}

函数式(SAM)接口

只有一个抽象方法的接口称为函数式接口,定义时可定义为 fun interface 接口名{ }

函数式接口可以有多个非抽象成员,但只能有一个抽象成员,且该成员为抽象函数,也就是说函数式接口无抽象变量

fun interface A{
    // val name:String //Fun interfaces cannot have abstract properties
    // fun printA() //Fun interfaces must have exactly one abstract method
    val name:String
        get()="123"
    fun printA(){
        println("This is a concrete method")
    }
    fun sayHello()
}

SAM转换

SAM转换可以使用lambda方便函数式接口的声明定义

首先来看非SAM转换使用函数式接口的例子(有两种方式:构建类实现或者使用匿名类)

fun interface A{
    // val name:String //Fun interfaces cannot have abstract properties
    // fun printA() //Fun interfaces must have exactly one abstract method
    val name:String
        get()="123"
    fun printA(){
        println("This is a concrete method")
    }
    fun sayHello()
}
class B:A{
    override fun sayHello() {
        println("This is class method")
    }
}
fun main(args:String){
    val a= object : A {
        override fun sayHello() {
            println("This is anonymity method")
        }
    }
    a.sayHello()
    val b=B()
    b.sayHello()
}

可以看到实现接口的方式较为简单,而匿名类则是通过变量=object:接口 { 重写方法}的方式

如果使用IDEA编写Kotlin时,会在匿名类使用处提示转lambda

使用lambda方式即是SAM转换,

语法:var/val 变量名=接口名{方法体}

val a= A{
        println("This is SAM method")
    }

类型别名

类型别名并没有创建新的类型,而是给原来的较长的类型名起一个更容易拼写的名字

类似C++中的typedef关键字,Kotlin中使用typealias关键字

类型别名需要定义在顶层(也就是与package定义同级)

语法是:typealias 新类型名=旧类型名

//定义集合别名
typealias SET_Int=Set<Int>
typealias MAP_II=Map<Int,Int>

//还可以定义类内的可访问的public成员类别名
class A{
    inner class B{

    }
}
typealias innerB=A.B

//还可以定义函数类型(参数+返回值)的别名,主要用于lambda函数
typealias fun_A=(Int,String)->Unit
fun doFun_A(a:fun_A){
    a(1,"2")
}

fun main(args:Array<String>){
    val fun_a:fun_A={ i: Int, s: String ->
        println(s+i)
    }
    doFun_A(fun_a)
}
//运行结果:21

Lambda函数的详细使用见后续

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值