web-dev-qa-db-ja.com

Kotlin:「静的な」継承可能な関数を作成するにはどうすればよいですか?

たとえば、Childを拡張する型Parentで関数example()を使用して、両方で関数を使用できるようにしたいとします。

_Child.example()
Parent.example()
_

これを行う最初の「明白な」方法は、Parentのコンパニオンオブジェクトを使用することですが、これはChildexample()を許可しません。

私が試した2番目の方法は、_Parent.Companion_で拡張関数を定義することでした。これは、コンパニオンオブジェクトを定義する必要があるため、不便です。また、Childexample()を使用することもできません。

誰か私がこれを行う方法を知っていますか?

24
Jire

あなたが求めているものは存在しません、あなたは尋ねているように見えます:

子孫のクラス参照からスーパークラスのコンパニオンオブジェクトメソッドを参照できますか

または多分あなたは尋ねています:

子孫の参照からスーパークラスの静的メンバーを参照できますか?.

両方の答えはnoです。これが許可されず、意識的な決定であり、意図的だったのは、Kotlinの設計によるです。この決定を変更したい場合は、 YouTrackで問題を報告 する必要があります。 Java was かなり混乱したのプログラマーは、静的メソッドの継承とオーバーライド、およびある参照から別の参照に対して呼び出されたときの動作と、動的ではなく静的に解決される方法によって。 Java 8チームが静的メソッドをインターフェースに追加すると混乱が生じる可能性があるため、インターフェース参照からの呼び出しのみを許可するというKotlinのアプローチを採用しました。これらのタイプの悪夢を回避するには、 Kotlinチームはそれを拒否し、Javaの他の多くの混乱する側面を拒否したのと同じように。

他の回答(@voddanなど)では、 companion objects を使用して構文を呼び出すのと同じ感覚を持つ回避策が提供されますが、コンパニオンオブジェクトを避けたいと言ってコメントでそれらを拒否します、あなたの質問はあなたがそれらを使おうとしていると述べていますが。したがって、それらを使用したくない場合、答えは単純にいいえ、実行できませんです。

コンパニオンオブジェクトを取り除くために、あなたは話したいと思います 拡張関数は「静的」な方法で呼び出すことができますか? ...これはまだ許可されていないので残念です。

コンパニオンオブジェクトに戻って(申し訳ありませんが、ここでは栄光への1つのパスです)、子のメソッドを手動で親に委任することもできます。

open class Parent {
    companion object { // required, sorry, no way around it!
        fun foo() = /* some cool logic here */
    }
}

class Child: Parent() {
    companion object {  // required, sorry, no way around it!
        fun foo() = Parent.foo() 
    }
}

または拡張機能として:

open class Parent {
    companion object {} // required, sorry, no way around it!
}

class Child: Parent() {
    companion object {} // required, sorry, no way around it!
}

fun Parent.Companion.foo() = /* some cool logic here */
fun Child.Companion.foo() = Parent.foo()
27
Jayson Minard

コンパニオンオブジェクトは他のオブジェクトと同じルールで再生されるため、通常のコード再利用手段を簡単に使用できます。

open class Example {
    fun example() {}
}

class Parent {
    companion object : Example()
}

class Child {
    companion object : Example()
}

fun main(args: Array<String>) {
    Child.example()
    Parent.example()
}

または、クラスの委任を使用して、Parentからの実装を直接再利用できます。

interface Example {
    fun example()
}

class Parent {
    companion object : Example {
        override fun example() {}
    }
}

class Child {
    companion object : Example by Parent.Companion
}
15
voddan

目的は、構築への「代替演算子」を作成することです

Javaでは、「コンストラクタ」として使用する場合、静的メソッドの代わりにファクトリを使用する必要があります。

Kotlin側では、ファクトリの代わりにトップレベル関数を使用できます。

または、クラスに「静的メソッド」が本当に必要な場合は、コンパニオンオブジェクトを作成し、静的拡張メソッドを追加します。

0
D3xter