原创

Kotlin中的接口

一、接口的定义

接口定义的基本语法:

[修饰符] interface 接口名 : 父接口1,父接口2...{
    0~N个属性定义...
    0~N个方法定义...
    0~N个嵌套类、嵌套接口、嵌套枚举定义...
}
  • 修饰符可以是public | internal | private中的任意一个,或完全省略修饰符。如果省略了访问控制符,则默认采用public。
  • 接口名应与类名采用相同的命名规则。接口名通常使用形容词。
  • 一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。

接口定义的是一种规范,因此接口中不能包含构造器和初始化块定义。

Kotlin接口与Java接口的区别:

  • Java接口中的所有成员都会自动使用public修饰,如果为这些成员指定访问权限,也只能指定public访问权限;
  • Kotlin接口中的成员可支持private和public两种访问权限。
interface Outputable {
    //只读属性定义了getter方法,非抽象属性
    val name: String
        get() = "输出设备"
    //只读属性没有定义getter方法,抽象属性
    val brand: String
    //读写属性没有定义getter、setter方法,抽象属性
    var category: String

    //接口中定义的抽象方法
    fun out()

    fun getDate(msg: String)

    //接口中定义的非抽象方法,可使用private修饰
    fun print(vararg msgs: String) {
        for (msg in msgs) {
            println(msg)
        }
    }

    fun test() {
        println("接口中的test()方法")
    }
}

二、接口的继承

接口的继承和类的继承不一样,接口支持多继承,即一个接口可以有多个直接父接口。

interface InterfaceA {
    val propA: Int
        get() = 5

    fun testA()
}

interface InterfaceB {
    val propB: Int
        get() = 6

    fun testB()
}

interface InterfaceC : InterfaceA, InterfaceB {
    val propC: Int
        get() = 7

    fun testC()
}

三、使用接口

接口不能用于创建实例,但可以用于声明变量。接口的主要用途就是被实现类实现。

接口的主要用途:

  • 定义变量,也可用于进行强制类型转换。
  • 被其他类实现。

实现接口可以获得所实现接口中定义的属性、方法。

package `0704`

interface Product {
    fun getProduceTime(): Int
}

const val MAX_CACHE_LINE = 10

class Printer : Outputable, Product {
    private val printData = Array<String>(MAX_CACHE_LINE, { "" })
    //用以记录当前需打印的作业数
    private var dataNum = 0
    //重写接口的抽象只读属性
    override val brand: String = "HP"
    //重写接口的抽象读写属性
    override var category: String = "输出外设"

    override fun out() {
        //只要还有作业,就继续打印
        while (dataNum > 0) {
            println("打印机打印:" + printData[0])
            //把作业队列整体前移一位,并将剩下的作业数减1
            System.arraycopy(printData, 1, printData, 0, --dataNum)
        }
    }

    override fun getDate(msg: String) {
        if (dataNum >= MAX_CACHE_LINE) {
            println("输出队列已满,添加失败")
        } else {
            //把打印数据添加到队列里,已保存数据的数量加1
            printData[dataNum++] = msg
        }
    }

    override fun getProduceTime(): Int {
        return 45
    }
}

fun main(args: Array<String>) {
    //创建一个Printer对象,当成Output使用
    var o: Outputable = Printer()
    o.getDate("Kotlin入门")
    o.getDate("Kotlin进阶")
    o.out()
    o.getDate("Kotlin高级")
    o.getDate("Kotlin实战")
    o.out()
    //调用Outputable接口中定义的非抽象方法
    o.print("刘备", "关羽", "张飞")
    o.test()
    //创建一个Printer对象,当成Product使用
    val p:Product=Printer()
    println(p.getProduceTime())
}

输出结果:

打印机打印:Kotlin入门
打印机打印:Kotlin进阶
打印机打印:Kotlin高级
打印机打印:Kotlin实战
刘备
关羽
张飞
接口中的test()方法
45

接口不能显式继承任何类,但所有接口类型的变量都可以直接赋给Any类型的变量。

四、接口和抽象类

接口和抽象类的相似之处如下:

  • 都不能被实例化,都位于继承树的顶端,用于被其他类实现和继承。
  • 都可以包含抽象成员,实现接口或继承抽象类的普通子类都必须实现这些抽象成员。

接口和抽象类的差别:

  • 接口作为系统与外界交互的窗口,体现的是一种规范。当在一个程序中使用接口时,接口是多模块之间的耦合标准;当在多个应用程序之间使用接口时,接口时多个程序之间的通信标准。
  • 抽象类作为系统中多个子类的共同父类,所体现的是一种模板模式设计。
  • 接口中不包含构造器;但抽象类中可以包含构造器,抽象类中的构造器并不是用于创建对象的,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
  • 接口中不能包含初始化块;但抽象类中则完全可以包含初始化块。
  • 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Kotlin单继承的不足。

学海无涯苦作舟

我的微信公众号.jpg

基本语法
  • 作者:HunterArley (联系作者)
  • 发表时间:2019-11-26 10:26
  • 版权声明:本网站部分内容转载于合作站点或其他站点,但都会注明作/译者和原出处。如有不妥之处,敬请指出。
  • 公众号转载:请在文末添加作者公众号二维码