Kotlin:インターフェース…コンストラクタはありません


138

Javaコードの一部をKotlinに変換していますが、Kotlinコードで定義されているインターフェースをインスタンス化する方法がよくわかりません。例として、インターフェース(Javaコードで定義)があります。

public interface MyInterface {
    void onLocationMeasured(Location location);
}

次に、さらにKotlinコードでこのインターフェイスをインスタンス化します。

val myObj = new MyInterface { Log.d("...", "...") }

そしてそれはうまくいきます。ただし、MyInterfaceをKotlinに変換すると、次のようになります。

interface MyInterface {
    fun onLocationMeasured(location: Location)
}

エラーメッセージが表示されます。Interface MyListener does not have constructorsインスタンス化しようとすると、構文以外は何も変更されていないようです。Kotlinでのインターフェースの動作を誤解していますか?

回答:


225

JavaコードはSAM変換(ラムダから単一の抽象メソッドを持つインターフェースへの自動変換)に依存しています。SAM変換は、現在 Kotlinで定義されているインターフェイスではサポートさていません。代わりに、インターフェースを実装する匿名オブジェクトを定義する必要があります。

val obj = object : MyInterface {
    override fun onLocationMeasured(location: Location) { ... }
}

14
どうもありがとう。あなたが投稿したリンクから、Location -> Unit可能であれば、単一メソッドのインターフェースの代わりに関数型(たとえば)を使用することが望ましいと理解しています-正しいですか?
アレフアレフ2017年

4
正しい。可能な限り関数型を使用する必要があります。
Yoav Sternberg

ただし、私の場合、インターフェイス(SurfaceTextureListener)には複数のメソッドがありました。
Tash Pemhiwa

本当にありがとう。この回答には、より多くのいいね!や特別なマークが必要です。これは非常に有用な情報であり、残念ながら、SAMトピックを見ると、記事や「Kotlin in Action」でKotlinを学ぶときに混乱する可能性があります。
TT_W 2019

「Kotlin in Action」から、はい、JavaのSAMパラメータでラムダを使用してコードを短く簡潔にできますが、KotlinのSAMではできません。関数型はKotlinの最初のクラスなので、SAMはKotlin、typealiasの関数型には意味がありませんよりKotlinスタイルです。
vg0x00

17

最善の解決策は、Javaインターフェースの代わりにtypealiasを使用することです

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {

}

次のように登録します。

val myObject = { location -> ...}
addLocationHandler(myObject)

またはもっとすっきり

addLocationHandler { location -> ...}

次のように呼び出します。

myInterface.invoke(location)

現在の3つのオプションは次のようです。

  • typealias(Javaから呼び出された場合は面倒)
  • kotlinインターフェース(kotlinから呼び出すと面倒です。オブジェクトを作成する必要があります)これはIMOの大きな一歩です。
  • javaインターフェース(kotlinから呼び出されたときに煩雑さが少なくなります。ラムダにはオブジェクト名が必要ないようにインターフェース名を前に付ける必要があります。また、関数の括弧の規則の外ではラムダを使用できません)

ライブラリをKotlinに変換するとき、実際にはすべてのインターフェイスをJavaコードに残しました。KotlinからKotlinを呼び出すよりも、KotlinからJavaを呼び出すほうがわかりやすいためです。


8

このようにあなたのインターフェースにアクセスしてみてください:

 object : MyInterface {
    override fun onSomething() { ... }
}

6

このようなJavaクラスがある場合:

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new RecyclerTouchListener.ClickListener()
        {
              //Your Code
        }));

このコードをJavaからKotlinに次のように変換する必要があります。

override fun showJozList (list : List<ResponseGetJuzList.Parameter4>) {
        adapter.addData(list)
        jozlist_recycler.addOnItemTouchListener(RecyclerTouchListener(
                activity ,
                jozlist_recycler ,
                object : RecyclerTouchListener.ClickListener
                    {
                          //Your Code
                    }))

Javaインターフェースの変換:

new RecyclerTouchListener.ClickListener()

Kotlinインタフェーススタイル:

object : RecyclerTouchListener.ClickListener

1

インターフェイスがクラスのリスナーメソッド用である場合は、インターフェイス定義を関数型に変更します。これにより、コードがより簡潔になります。以下を参照してください。

リスナー定義を含むクラス

// A class
private var mLocationMeasuredListener = (location: Location) -> Unit = {}

var setOnLocationMeasuredListener(listener: (location: Location) -> Unit) {
    mLocationMeasuredListener = listener
}

// somewhere in A class
mLocationMeasuredListener(location)

別のクラス

// B class
aClass.setOnLocationMeasuredListener { location ->
    // your code
}

-1
class YourClass : YourInterface {  
    override fun getTest() = "test"    
}

interface YourInterface {
    fun getTest(): String
}

val objectYourClass: YourInterface = YourClass()
print(objectYourClass.getTest())
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.