一般接口
Kotlin 中接口和 Java 的接口关键字是一样的,也是通过 interface 来定义一个接口,在 Java 中我定义接口通常如下:
// 接口
interface MyInterface{
void foo();
}
// 实现类
class MyImpl implement MyInterface{
@override
void foo(){
//TODO
}
}
在 Kotlin 中,我们定义接口和 Java 中一样,不过就是因为Kotlin 的方法是有关键字 fun
修饰
// 接口
interface MyInterface{
fun foo()
}
// 实现类
class MyImpl:MyInterface{
override fun foo(){
//TODO
}
}
这里看上去和 Java 几乎是一模一样,而在 Java8 之后支持接口里面的默认方法例如
// 接口
interface MuInterface{
void foo();
default void bar(){
// TODO
}
}
// 实现类
class MyImpl implement MyInterface{
@override
void foo(){
//TODO
}
}
kotlin 如此先进的语言肯定也是支持默认方法的,甚至更胜一筹
// 接口
interface MyInterface{
fun foo()
fun bar(){
//TODO
}
}
// 实现类
class MyImpl:MyInterface{
override fun foo(){
//TODO
}
}
我们将 两段kotlin 的代码反编译为 Java 代码看下:
// 没有默认方法的接口
public interface MyInterface {
void foo();
}
// 有默认方法的接口
public interface MyInterface {
void foo();
void bar();
public static final class DefaultImpls {
public static void bar(@NotNull MyInterface1 $this) {
// TODO
}
}
}
通过反编译的代码我们看到,其实默认方法的是通过在接口内部创建了一个静态内部类来实现的DefaultImpls
,如果调用接口默认的方法,则会调用到内部类的静态方法。这也就解释了为什么在低版本的 jdk 上也可以使用默认方法了。(起初 kotlin 的 jdk 版本为1.6)
接口继承
接口的继承和类的继承一样,使用:
表示继承关系,示例:
interface MyInterface1 {
fun foo()
}
interface MyInterface2:MyInterface1{
fun bar()
}
多继承问题
我们学习 Java 接口的时候经常会使用鸟类来举例子,那么这里我们也是用这个来举例:我们假设有两个接口Animal
,Flyer
,Bird
定义如下:
interface Flyer{
fun fly()
fun eat()
}
interface Animal {
fun eat()
}
class Bird:Flyer,Animal{
override fun fly() {
println("i can fly")
}
override fun eat() {
println("i can eat")
}
}
这里还比较常见,可以通过复写 eat 方法即可,我们再看下面这个例子
public interface InterfaceA {
default void foo(){
System.out.println("foo");
}
void bar();
}
public interface InterfaceB {
default void foo(){
System.out.println("foo");
}
default void bar(){
System.out.println("bar");
}
}
public class MyImplB implements InterfaceA,InterfaceB{
@Override
public void foo() {
InterfaceA.super.foo();
InterfaceB.super.foo();
}
@Override
public void bar() {
InterfaceB.super.bar();
}
}
这里因为有默认方法,而且两个接口方法名称还是一样的,实现的时候我们实现类中通过**接口名.super.方法名
,实现 super,那么这个在 kotlin 中怎么实现呢,kotlin 可以通过super<接口名>.方法名
**,做到指定方法实现,代码如下
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接口
只有一个抽象方法的接口就是 函数式接口,这个在 Android 中很常见,比如各种监听。而这类函数式接口,可以在 interface 之前,添加一个 fun,表示这是一个函数式接口
fun interface MyInterface{
fun foo()
}
这样做有什么好处呢?我们之前在学习 object 的时候提到过,如果方法只有一个,是可以通过 lambda 表示来减少代码,使代码简洁明了。
例如通常我们这么定义的接口和实现
interface A {
fun foo()
}
fun main() {
val a: A = object : A {
override fun foo() {
TODO("Not yet implemented")
}
}
}
因为 A 接口中只有一个方法,所以我们通过函数式接口来做的话就是
fun interface A {
fun foo()
}
fun main() {
val a: A = A { TODO() }
}
这里很像我们之前写click 监听写了一大串 new xxlistener,然后里面 override xx 方法,通过 Java8 的 lambda 表达式只需要new xxlistener(()->{ xxx})
这样简单明了。