kotlin和Java一样只支持类的单继承。
1.接口实现多继承
kotlin中的接口与Java很相似,但它除了可以定义带默认实现的方法之外,还可以声明抽象的属性。
用kotlin接口实现多继承
package com.example.kotlindemo.classsdemo
interface PayKFlyer {
fun fly()
fun kind() = "flying animalsA"
}
interface PayKAnimal {
val name: String
fun eat()
fun kind() = "flying animalsB"
}
class PayKoBird(override val name: String) : PayKFlyer, PayKAnimal {
override fun fly() {
println("I can fly")
}
override fun eat() {
println("I can fly")
}
override fun kind() = super<PayKFlyer>.kind()
}
fun main() {
val bird = PayKoBird("sparrow")
println(bird.kind())
}
flying animalsA
Kotlin转java
public interface PayKFlyer {
void fly();
@NotNull
String kind();
public static final class DefaultImpls {
@NotNull
public static String kind(PayKFlyer $this) {
return "flying animalsA";
}
}
}
public interface PayKAnimal {
@NotNull
String getName();
void eat();
@NotNull
String kind();
public static final class DefaultImpls {
@NotNull
public static String kind(PayKAnimal $this) {
return "flying animalsB";
}
}
}
public final class PayKoBird implements PayKFlyer, PayKAnimal {
@NotNull
private final String name;
public void fly() {
String var1 = "I can fly";
System.out.println(var1);
}
public void eat() {
String var1 = "I can fly";
System.out.println(var1);
}
@NotNull
public String kind() {
return PayKFlyer.DefaultImpls.kind(this);
}
@NotNull
public String getName() {
return this.name;
}
public PayKoBird(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
}
}
public static final void main() {
PayKoBird bird = new PayKoBird("sparrow");
String var1 = bird.kind();
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
如果是同时存在相同的属性名:
interface PayKFlyer {
val name: String
get() = "ooo"
fun fly()
fun kind() = "flying animalsA"
}
interface PayKAnimal {
val name: String
fun eat()
fun kind() = "flying animalsB"
}
class PayKoBird2() : PayKFlyer, PayKAnimal {
override val name: String
get()=super<PayKFlyer>.name
override fun fly() {
println("I can fly")
}
override fun eat() {
println("I can fly")
}
override fun kind() = super<PayKFlyer>.kind()
}
Kotlin通过super关键字,来指定继承哪一个父接口,(super<PayKFlyer>.kind()),也可以直接覆盖父接口的方法。
Kotlin实现接口的相关语法
1.在Kotlin实现一个接口时,需要实现接口中没有默认实现的方法及未初始化的属性,若同时实现多个接口,而接口之间有相同方法名的默认实现时,需要通过super关键字来
指定使用哪一个接口的方法或者直接重写这个方法。
2.如果是默认的接口方法,可以在实现类中通过"super<T>"这种方式调用它,其中T为拥有该方法的接口名。
3.在实现接口的属性和方法时,都必须带上override关键字,不能省略。
上面代码中是通过主构造函数的方式来实现接口中的name属性的,(其实通过val声明的构造方法参数,其实是在类内部定义了一个同名属性)
class PayKoBird3(name:String):PayKFlyer, PayKAnimal {
override val name:String
init {
this.name = name
}
override fun fly() {
println("I can fly")
}
override fun kind() = super<PayKFlyer>.kind()
override fun eat() {
println("I can fly")
}
}
getter和setter注意点:
1.用val声明的属性将只有getter方法,因为它不可修改;而用var修饰的属性将同时拥有getter和setter方法。
2.用private修饰的属性编译器将会省略掉getter和setter方法,因为在外部类已经无法访问它了,这两个方法就没有存在的意义了。
内部类解决多继承的方案
由于内部类可以继承一个与外部无关的类,所以保证了内部类的独立性,从而可以解决多继承的问题。
在kotlin中定义一个内部类,需要inner关键字。
package com.example.kotlindemo.classsdemo
class PayOuterKotlin {
val name = "This is truely kotlin's inner class."
inner class PayInnerKotlin {
fun println() {
println("the name is $name")
}
}
}
内部类与嵌套类
在Java中,通过在内部类的语法上增加一个static关键字,把它变成嵌套类。而kotlin是默认是一个嵌套类,必须加上一个inner关键字才是一个内部类,也就是把静态的内部类看出嵌套类。
内部类与嵌套类(静态内部类)的区别
内部类包含着对其外部类实例的引用,在内部类中我们可以使用外部类中的属性。而嵌套类不包含对其外部类实例的引用,所以无法调用其外部类的属性。
open class PayHorse {
fun runFast() {
println("I can run fast")
}
}
open class PayDonkey {
fun doLongTimeThing() {
println("I can do some thing long time")
}
}
class Mule {
fun runFast() {
HorseC().runFast()
}
fun doLongTimeThing() {
DonkeyC().doLongTimeThing()
}
private inner class HorseC : PayHorse()
private inner class DonkeyC : PayDonkey()
}
注意点:
1.一个类内部可以定义多个内部类,每个内部类的实例都有自己独立的状态,它们与外部对象的信息相互独立。
2.通过让内部类继承不同的类,就可以让外部类同时获得内部类所继承类的状态和行为。
3.利用private修饰内部类,使得其他类不能访问内部类,具有良好的封装性。
使用委托替代多继承
kotlin 新引入的语法——委托。
委托是一种特殊类型,用于方法事件委托。
通过by关键字可以实现委托效果,by lazy就是利用委托实现的延迟初始化语法。
class TestLazy{
val laziness:String by lazy{
println("I will have a value")
"I am a lazy-initialized string"
}
}
fun main() {
val testLazy = TestLazy()
val laziness = testLazy.laziness
println(laziness)
}
使用委托解决多继承问题
interface PayCanFly {
fun fly()
}
interface PayCanEat {
fun eat()
}
open class PayFlyer : PayCanFly {
override fun fly() {
println("I can fly")
}
}
open class PayAnimal : PayCanEat {
override fun eat() {
println("I can eat")
}
}
class PayAnimalBird(flyer: PayFlyer, animal: PayAnimal) : PayCanFly by flyer, PayCanEat by animal {
}
fun main() {
val fly = PayFlyer()
val animal = PayAnimal()
val b = PayAnimalBird(fly, animal)
b.fly()
b.eat()
}
I can fly
I can eat
使用委托的优势
1.接口是无状态的,所以即使提供了默认方法实现也是较简单的,不能实现复杂的逻辑,也不推荐在接口中实现复杂的方法逻辑。可以利用委托的方式,虽然也是委托接口,
但它是用一个具体的类去实现方法逻辑,拥有更强的能力。
2.假设需要继承的类是A,委托对象是B、C,在具体调用的时候并不像组合一样A.B.method,而是可以直接调用A.method,这更能表达A拥有该method的能力,更加直观,虽然背后是通过委托对象来执行具体方法逻辑的。
参考kotlin核心编程