Kotlinの抽象化とインターフェース
実際、Kotlinの継承とインターフェースのほとんどはJavaと同じですが、文法レベルでのサポートは異なります。Kotlinには、特定の文法を簡単かつ効率的に宣言できるシンタックスシュガーのレイヤーがあるため、文法コードテンプレートではなく、ビジネスロジックに集中できます。次に、Kotlinでの多重継承の実装について説明します。KotlinとJavaはどちらも単一継承です。これは疑う余地がありませんが、多重継承シナリオも必要になります。では、Kotlinはこのようなシナリオをどのように解決するのでしょうか。誰もがインターフェースの多重継承を考えているに違いありません。見てみましょう。
1.抽象化とインターフェース
Javaと同様に、Kotlinも 抽象クラスとインターフェースを個別に使用 abstract
し interface
て宣言します。さらに、Kotlinのインターフェースは非抽象メソッドの実装もサポートします(これはJava8のデフォルトのメソッドと非常に似ています)が、注意が必要です。内部。任意の状態(純粋な関数の形式)。
1.1抽象クラス宣言
Kotlinでは、抽象クラスの宣言は abstract
キーワードを使用し、抽象クラスのabstract
メソッドは宣言型の抽象メソッドを使用し ます。
//以Random.kt源码为例
public abstract class Random {//使用abstract关键声明一个抽象类Random
public abstract fun nextBits(bitCount: Int): Int //与Java一样使用abstract声明一个抽象类中抽象方法,所以子类必须要实现该方法
public open fun nextInt(): Int = nextBits(32)//open表示这个类可以被子类重写
public fun nextInt(until: Int): Int = nextInt(0, until)//由于Kotlin默认是final且没有显式open,所以该方法不能被子类重写
...
}
1.2インターフェースステートメント
Kotlinのインターフェース宣言はinterface
キーワードを使用します :
interface OnClickListener {//使用interface关键字声明一个接口
fun onClick() //声明了一个接口抽象方法,所有实现这个接口的非抽象类都需要实现这个方法
}
Kotlinにシンプルなインターフェースを実装する
class Button: OnClickListener {
override fun onClick() = println("Button is Clicked") //与Java不同的是在Kotlin中override必须是强制要求的
}
2.Kotlinのデフォルトメソッドとのインターフェース
次のバージョンのJava8では、インターフェースに実装メソッドがないことは誰もが知っています。default
Java 8にメソッドが存在するまでは 、実装されたメソッドをJava8で宣言できます。
//java8实现
public interface OnClickListener {
public void onClick();
default public void onClickLog() {//使用default关键字声明接口中一个带实现的方法,这个Java8以下版本是无法做到
System.out.println("clicked!");
}
}
Java 8でデフォルトのメソッドを使用してインターフェースを実装する方法を見てきましたが、Kotlinではどのように実装されていますか?実際、Kotlin構文は、デフォルトの実装を持つメソッドを自然にサポートしており、キーワードや修飾子を追加する必要はありません。
//kotlin实现
interface OnClickListener {
fun onClick()
fun onClickLog() = println("clicked!")//不需要声明任何关键字,直接支持带默认实现的方法
}
KotlinはJava6と完全に互換性があることは誰もが知っています。ただし、デフォルトで実装されているこのインターフェイスメソッドはJava8ではサポートされていません。では、KotlinはJava8より前のバージョンでこの文法機能とどのように互換性があるのでしょうか。Kotlinコードを一目で逆コンパイルします。
//反编译后java代码
public interface OnClickListener {
void onClick();
void onClickLog();
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 3
)
public static final class DefaultImpls {//可以看到这边自动生成一个DefaultImpls静态类
public static void onClickLog(OnClickListener $this) {//默认实现方法onClickLog被声明成一个静态方法
String var1 = "Clicked!";
boolean var2 = false;
System.out.println(var1);
}
}
}
上記のコードはあまり直感的ではなく、どのようにDefaultImpls
呼び出しがトリガーされるのかわからない場合は 、上記のコードを実装クラスに追加して、どのように呼び出されるかを確認できます。
package com.imooc.test
interface OnClickListener {
fun onClick()
fun onClickLog() = println("Clicked!")
}
class Button : OnClickListener {//Button实现类
override fun onClickLog() {//重写onClickLog方法
super.onClickLog()//默认通过super调用父类默认实现的方法
}
override fun onClick() {
}
}
逆コンパイルされたJavaコード
// OnClickListener.java
public interface OnClickListener {
void onClick();
void onClickLog();
@Metadata(
mv = {1, 1, 16},
bv = {1, 0, 3},
k = 3
)
public static final class DefaultImpls {
public static void onClickLog(OnClickListener $this) {
String var1 = "Clicked!";
boolean var2 = false;
System.out.println(var1);
}
}
}
// Button.java
public final class Button implements OnClickListener {
public void onClickLog() {
OnClickListener.DefaultImpls.onClickLog(this);//现在可以看到实际上通过接口类名调用它内部静态类DefaultImpls,再通过静态类DefaultImpls调用它的静态方法onClickLog
}
public void onClick() {
}
}
要約すると、デフォルト実装のKotlinインターフェイスが次のバージョンのJava8とどのように互換性があるか、実際には内部インターフェイスにあり、静的クラスを生成し、静的クラス DefaultImpls
の内部静的メソッドの対応するデフォルト実装を生成します。次に、呼び出すときにインターフェイス名を渡すだけで済みます。静的クラス DefaultImpls
。静的メソッド名呼び出しのデフォルトの実装は次のようになります。
3.Kotlinでのインターフェースの多重継承
Javaでは多重継承がサポートされていないことは誰もが知っていますが、Kotlinはクラスの多重継承もサポートしていません。しかし、なぜこのように設計されているのでしょうか。しかし、多くの小さなパートナーがこのような感覚を持っているはずであり、通常の開発では依然として複数の継承シナリオに遭遇していると思います。
3.1クラスの多重継承をサポートしないのはなぜですか
一般に「ダイヤモンド継承問題」として知られている古典的な多重継承問題を誰もが知っていると思います。Java / Kotlinがクラスの多重継承をサポートしていると仮定して、矛盾メソッドを使用します。例を見てみましょう。クラスAにはinvokeメソッドがあります。クラスBとCの両方がクラスAを継承し、次にクラスDがクラスBを継承します。個別に。、クラスC。
abstract class A {
abstract fun invoke()
}
class B: A {
override fun invoke() = println("B invoke")
}
class C: A {
override fun invoke() = println("C invoke")
}
class D: B,C {//假设支持类的多继承
override fun invoke() = println("C invoke")// B ? C
}
したがって、問題は、クラスDがクラスBのinvokeメソッドまたはクラスCのinvokeメソッドを継承する必要があるかどうかです。したがって、そのようなクラスの多重継承は、簡単にあいまいさをもたらす可能性があります。
ただし、開発プロセスで多重継承の問題が発生する可能性があることはわかっています。JavaとKotlinではインターフェースの多重継承がサポートされていることがわかっているため、一般的に使用される方法は、インターフェースの多重継承を使用して解決することです。
3.2Kotlinでのインターフェースの多重継承
Javaではインターフェイスの多重継承がサポートされていますが、Kotlinは引き続きサポートしています。では、Kotlinで上記の多重継承問題を解決する方法を見てみましょう。
package com.imooc.test
interface A {
fun invoke()
}
interface B : A {
override fun invoke() {
println("B invoke")
}
}
interface C : A {
override fun invoke() {
println("C invoke")
}
}
class D : B, C {
//override fun invoke() = super<B>.invoke()//通过super中泛型类型指定继承B接口的方法,所以最后输出"B invoke"
override fun invoke() = super<C>.invoke()//通过super中泛型类型指定继承C接口的方法,所以最后输出"C invoke"
}
fun main() {
val d = D()
d.invoke()
}
4.まとめ
これでKotlinの抽象化とインターフェースは終わりです。実際、Kotlinの抽象化とインターフェースは基本的にJavaのものと似ています。記事に記載されている違いに注意してください。