接口

2018-06-15  本文已影响0人  一江碎月

使用 interface 关键字定义一个接口

  1. 接口中的方法可以有默认实现。

  2. 如果子类实现的接口中有相同的有默认实现的方法,子类 必须重写该方法

    如下面两个接口中,都有相同的有实现的 t(),也有相同的没有实现的 at()。子类实现时,两个方法必须都重写。

    而对于没有冲突的 s() 子类不需要重写。调用时直接使用父类的实现逻辑。

    interface Itf{
        fun t()= "itf"//含有实现的方法
        fun at()
        fun s()=println("没有冲突方法")
    }
    interface Itf2{
        fun t()= "itf2"//含有实现的方法
        fun at()
    }
    
    class Impl:Itf,Itf2{
        override fun at()= println("实现")
        override fun t()="hh"
    }
    
    fun main(args: Array<String>) {
        val i=Impl()
        i.at()// 实现
        i.s()
        println(i.t())// hh
    }
    
  3. 接口中的成员始终是 open 的,没有实体的方法始终是 abstract(该关键字不不是必需)。因此,接口中的任何方法都可以被继承、重写

定义属性

接口中可以定义属性。接口并没有指定属性是通过一个字段存储还是通过 getter 获取。

属性重写时,前面也需要加上 override

  1. 接口可以定义抽象属性,由子类提供获取方法或存储

    interface Parent {
        val name: String
    }
    
    // 通过字段存储
    class Child(override val name: String) : Parent
    
    class Child2 : Parent {
        override val name: String
            get() {  // 通过 getter 获取
                println("c2 get")
                return "c222"
            }
    }
    
    class Child3 : Parent {
        override val name = getName2("aaa@xx") // 赋值初始化
    
        private fun getName2(s: String): String {
            println("c3 get")
            return s.substringBefore("@")
        }
    }
    

    上述三个子类说明了接口并不要求子类如何实现属性,只要求能从子类中获取指定属性

    要注意第二个与第三个的区别:第二个每一次获取时都会执行 getter 方法。而第三个只会执行一次,并将结果存储于 name 属性中,多次获取时直接读取 name 存储的值。

  2. 可以为属性定义 setter / getter。

    interface Parent {
       val name: String
       val age: Int
           get() = 10
    }
    
    class Child:Parent{
       override val name = "name"
    }
    

函数式接口

又称 SAM 接口(SAM 表示单抽象方法)。是指那些只有一个抽象方法的接口。

可以将方法的实现写成 lambda ,然后使用将 lambda 传入使用该接口实例的方法中。

本段代码使用了 android 中的 Handler 及 Log 两个类。post 方法需要的是 Runnable 对象,这里直接传递一个 lambda 用来代替 Runnable 对象:

fun main(args:Array<String>){
    Handler().post{
        Log.e("TAG","hhhh")
    }
}

构造函数

上述只是使用 lambda 代替 sam 实例,如果想创建一个 sam 实例,就需要使用构造函数:

构造函数由编译器自动生成,用于从 lambda 到实例的显式转换

  1. SAM 构造方法的名称与底层接口的名称一致。SAM 构造函数只接收一个参数 —— 一个被用作抽象方法体的 lambda 表达式 ——并返回一个这个接口的实例

  2. 用于构造 SAM 实例的 lambda 表达式中 不能引用 this,没有办法引用到转换成的实例对象

fun main(args: Array<String>) {
    val r = Runnable { // 此处的 runnable 是一个函数,而不是一个类
        println("lambda 啊")
    }
    Thread(r).start() // lambda 啊
}

上一篇下一篇

猜你喜欢

热点阅读