Kotlin:Interface ...没有构造函数

Ale*_*eph 109 java kotlin

我正在将我的一些Java代码转换为Kotlin,我不太了解如何实例化Kotlin代码中定义的接口.作为一个例子,我有一个接口(在Java代码中定义):

public interface MyInterface {
    void onLocationMeasured(Location location);
}
Run Code Online (Sandbox Code Playgroud)

然后在我的Kotlin代码中进一步实例化这个接口:

val myObj = new MyInterface { Log.d("...", "...") }
Run Code Online (Sandbox Code Playgroud)

它工作正常.但是,当我将MyInterface转换为Kotlin时:

interface MyInterface {
    fun onLocationMeasured(location: Location)
}
Run Code Online (Sandbox Code Playgroud)

我收到一条错误消息:Interface MyListener does not have constructors当我尝试实例化它时 - 虽然在我看来除了语法之外没有任何改变.我是否误解了Kotlin界面的工作原理?

yol*_*ole 186

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

val obj = object : MyInterface {
    override fun onLocationMeasured(location: Location) { ... }
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢.从您发布的链接中,我了解最好使用功能类型(例如`Location - > Unit`)而不是单方法接口(如果可能) - 这是正确的吗? (13认同)
  • 它是正确的.您应该尽可能使用功能类型. (4认同)

Ste*_*gin 16

最好的解决方案是使用Java接口的类型

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {

}
Run Code Online (Sandbox Code Playgroud)

像这样注册:

val myObject = { location -> ...}
addLocationHandler(myObject)
Run Code Online (Sandbox Code Playgroud)

甚至更清洁

addLocationHandler { location -> ...}
Run Code Online (Sandbox Code Playgroud)

像这样调用它:

myInterface.invoke(location)
Run Code Online (Sandbox Code Playgroud)

目前的3种选择似乎是:

  • typealias(从java调用时很乱)
  • kotlin接口(从kotlin调用时很乱;你需要创建一个对象)这是IMO的一大步.
  • java接口(从kotlin调用时不那么杂乱; lambda需要前缀的接口名称,所以你不需要一个对象;也不能在函数括号约定之外使用lambda)

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


ikn*_*now 9

Kotlin 中定义的接口支持 SAM 转换,因为 1.4.0

Kotlin 的新变化 1.4.0

在 Kotlin 之前1.4.0,您只能在使用 Kotlin 的Java 方法和 Java 接口时应用 SAM(单一抽象方法)转换。从现在开始,您也可以对 Kotlin 接口使用 SAM 转换。为此,请使用fun修饰符将 Kotlin 接口显式标记为具有功能性。

如果您将 lambda 作为参数传递,而预期只有一个抽象方法的接口作为参数,则 SAM 转换适用。在这种情况下,编译器会自动将 lambda 转换为实现抽象成员函数的类的实例。

所以你的问题中的例子看起来像这样:

fun interface MyInterface
{
    fun onLocationMeasured(location: String)
}

fun main()
{
    val myObj = MyInterface { println(it) }

    myObj.onLocationMeasured("New York")
}
Run Code Online (Sandbox Code Playgroud)

  • +1“使用 fun 修饰​​符将 Kotlin 接口显式标记为函数式”。没有它,什么都行不通。 (4认同)

Adn*_*aki 6

如果您有这样的Java类:

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

你应该把这个代码从Java转换成Kotlin,如下所示:

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

转换Java接口:

new RecyclerTouchListener.ClickListener()
Run Code Online (Sandbox Code Playgroud)

Kotlin界面风格:

object : RecyclerTouchListener.ClickListener
Run Code Online (Sandbox Code Playgroud)


Jéw*_*ôm' 6

尝试像这样访问您的界面:

 object : MyInterface {
    override fun onSomething() { ... }
}
Run Code Online (Sandbox Code Playgroud)