java 接口与面向对象_面向对象:抽象类和接口

抽象类和接口是面向对象的高级特性,Kotlin 中的抽象类和接口与 Java 8 类似。

1. 抽象类

Kotlin 中将一个类声明为抽象类的方式与 Java 相同,使用 abstract 关键字:

abstract class 抽象类名[(主构造函数)][: 继承父类和实现接口] {……}

我们之前提到,Kotlin 中的类默认不可继承,但抽象类本身就是为继承设计的,因此 即使不用 open 关键字修饰,抽象类也是可以被继承的 ,同样,使用 abstract 关键字修饰的抽象函数也可以不加 open。但是抽象类中的非抽象方法如果不用 open 修饰的话,还是不能被子类覆盖。

除了上面两点外,Kotlin 的抽象类与 Java 抽象类的用法基本相同。

2. 接口

Kotlin 的接口与 Java 8 中的接口类似,使用 interface 关键字定义接口,允许方法有默认实现:

interface KotlinInterface {

var prop: Int

fun foo(prop: Int)

fun bar() {

println("bar")

}

}

从上面代码可以发现 Kotlin 接口的几个细节:Kotlin 接口不能有构造函数,也就是说 Kotlin 接口定义时,接口名后是不能加主构造函数的;

Kotlin 接口中函数可以有默认实现,也可以没有,区别只在于函数有没有函数体,这与 Java 8 中需要用 default 关键字声明有默认实现的方法有所不同;

Kotlin 接口允许存在抽象变量,上面的定义的 prop 变量,实际上会被编译为 getProp(): Int 和 setProp(Int) 两个抽象方法,Kotlin 子类在实现接口时只需要用 override 覆盖这个属性,Java 子类在实现接口时需要先定义一个字段,然后实现这两个方法;

Kotlin 接口的属性只能是抽象的,也就是说 Kotlin 不允许像 Java 那样,在接口中定义 public static final 的全局常量。这点是因为 Kotlin 会把接口中定义的属性编译为 getter 和 setter 方法,而 Kotlin 字节码的版本只相当于 Java 6,不支持 Java 8 中的接口默认实现,所以不能给变量加上初始化语句。

------- 2017.5.27 更新 ----------

有小伙伴问到了默认方法的实现,在这里回答一下,让更多的人看到。

Kotlin 目前的目标字节码还停留在 JDK 1.6 版本,而 Java 直到 JDK 1.8 才支持接口添加默认实现,所以 Kotlin 在编译有默认实现的接口方法时,必须用一些“奇技淫巧”,用一些妥协的办法:

特殊的编译方式:静态内部类

没有默认实现的 Kotlin 接口方法,编译后与 JDK 1.8 之前的接口方法并无区别。而有默认实现的 Kotlin 接口方法会被编译为两个方法:一个是在接口里,没有默认实现,用来让子类继承;另一个在名为 DefaultImpls 的静态内部类里,我们给方法定义的默认实现就被编译器搬到了这里,同时添加了一个接口类型的参数。

比如我们上面举的 KotlinInterface 接口就会被编译下面的样子:

public interface KotlinInterface {

public abstract int getProp();

public abstract void setProp(int value);

public abstract void foo(int prop);

public abstract void bar();

public static final class DefaultImpls {

public static void bar(KotlinInterface $this) {

System.out.println("bar");

}

}

}

特殊的实现方式:自动实现默认方法

在实现有默认实现方法的 Kotlin 接口时,如果没有覆盖默认实现方法,Kotlin 编译器会自动添加一个实现方法:直接调用 DefaultImpls 类的方法;如果覆盖了默认实现方法,就不会再添加这个方法了。

比如,我们添加一个 KotlinInterfaceImpl 类,它实现了 KotlinInterface 接口,但没有实现 bar() 方法:

class KotlinInterfaceImpl : KotlinInterface {

// getProp(), setProp() override fun foo(value: Int) = value

}

反编译这个类,发现编译器已经帮我们实现了 bar() 方法:

public class KotlinInterfaceImpl implements KotlinInterface {

// getProp(), setProp() @Override

public int foo(int value) {

return value;

}

@Override

public void bar(KotlinInterface $this) {

return KotlinInterface.DefaultImpls.bar(this);

}

}

这样,我们就能直接调用 KotlinInterfaceImpl 类对象的 bar() 方法了,它实际上调用的是 KotlinInterface.DefaultImpls.bar() 方法。

总结一下,Kotlin 通过静态内部类 + 添加默认实现方法的方式实现了 JDK 1.6 中不支持的接口默认方法,给接口的设计带来了便利。当用 Java 编写 Kotlin 接口的实现类时,需要注意到这一点,可以通过调用 DefaultImpls 类的方法来使用接口提供的默认实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值