接口

作者: 一江碎月 | 来源:发表于2018-06-15 09:59 被阅读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 啊
    }
    

    相关文章

      网友评论

          本文标题:接口

          本文链接:https://www.haomeiwen.com/subject/xfepeftx.html