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中的接口如何工作?

Answers:


225

您的Java代码依赖于SAM转换-使用单个抽象方法将lambda自动转换为接口。Kotlin中定义的接口当前不支持 SAM转换。相反,您需要定义一个实现该接口的匿名对象:

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

14
非常感谢。从您发布的链接中,我了解,Location -> Unit如果可能的话,最好使用函数类型(例如)而不是单方法接口-正确吗?
Aleph Aleph

4
它是正确的。您应该尽可能使用函数类型。
Yoav Sternberg'5

但是在我的情况下,接口(SurfaceTextureListener)具有多种方法。
Tash Pemhiwa

非常感谢。这个答案必须有更多的喜欢或特殊标记,因为它是非常有用的信息,但是不幸的是,某些学习者在按文章或按“ Kotlin in Action”学习SAM主题时学习Kotlin时会感到非常困惑。
TT_W

来自“ Kotlin in Action”,是的,您可以在Java的SAM参数中使用lambda来缩短代码和使代码更整洁,但不能使用Kotlin的SAM,函数类型是Kotlin的第一类,因此,SAM对于Kotlin而言没有意义,带有typealias的函数类型是科特林风格。
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调用时,不会太混乱; lambda需要在接口名称前加上前缀,因此您不需要对象;也不能在函数括号约定之外使用lambda)

当将我们的库转换为Kotlin时,我们实际上将所有接口都保留在Java代码中,因为从Kotlin调用Java比从Kotlin调用Kotlin更干净。


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())
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.