首页 Kotlin学习笔记(6) - 接口
文章
取消

Kotlin学习笔记(6) - 接口

一、接口声明

Kotlin中的接口可以既包含抽象方法的声明也包含实现,与抽象类不同之处在于不能保存状态。接口内可以定义属性,但这些属性必须是抽象的或提供了访问器的实现(getter)

1
2
3
4
5
6
7
8
9
interface MyInterface {
    var age:Int // abstract
    val name: String
        get() = "lee"
    fun bar()
    fun foo() {
        // 可选的方法体
    }
}

二、接口实现

与java相同一个类或对象可以实现多个接口

1
2
3
4
5
class Child : MyInterface {
    override fun bar() {
        // body
    }
}

三、接口中的属性

接口中属性必须是抽象的或着提供了getter的实现,接口中属性没有 backing fields,不能够在接口中的属性直接引用。

1
2
3
4
5
6
7
8
9
10
11
12
interface MyInterface {
    var age:Int // abstract
    val name: String
        get() = "lee"
    fun foo() {
        // 可选的方法体
    }
}

class Child : MyInterface {
    override val age: Int = 29
}

四、接口继承

接口可以从其他接口派生,既可以给其他成员提供实现也可以声明新的函数和属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Named {
    val name: String
}

interface Person : Named {
    val firstName: String
    val lastName: String

    override val name: String get() = "$firstName $lastName"
}

data class Employee(
    // implementing 'name' is not required
    override val firstName: String,
    override val lastName: String,
    val position: Position
) : Person

五、处理覆盖冲突

与继承的规则相同,存在同名方法是,使用super<Base>来调用具体方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

六、函数式(SAM)接口 - Single Abstract Method

1. 函数式接口声明

函数式接口可以有多个非抽象成员,但只能有一个抽象成员,声明时使用fun修饰

1
2
3
fun interface KRunnable {
   fun invoke()
}

2. SAM转换

使用SAM转换,通过lambda表达式可以让代码更简单易读,而不是手动创建函数实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun interface IntPredicate {
   fun accept(i: Int): Boolean
}

// Creating an instance of a class
val isEven = object : IntPredicate {
   override fun accept(i: Int): Boolean {
       return i % 2 == 0
   }
}

//SAM conversions
val isEven = IntPredicate { it % 2 == 0 }

fun main() {
   println("Is 7 even? - ${isEven.accept(7)}")
}

3. 类型别名

上面的接口我们可以通过类型别名直接定义,达到同样的效果,使用typealias

1
2
3
4
5
6
7
typealias IntPredicate = (i: Int) -> Boolean

val isEven: IntPredicate = { it % 2 == 0 }

fun main() {
   println("Is 7 even? - ${isEven(7)}")
}

需要注意类型别名只能有一个成员,函数式接口可以有多个非抽象成员,而且可以实现和扩展其他接口

本文由作者按照 CC BY 4.0 进行授权

Kotlin学习笔记(5) - 属性

Kotlin学习笔记(7) - 可见修饰符