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

我正在将我的一些 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 的工作原理?

63670 次浏览

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

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

最好的解决方案是在 Java 接口中使用类型别名

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {


}

这样登记:

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

甚至更干净

addLocationHandler { location -> ...}

像这样调用它:

myInterface.invoke(location)

目前的三种选择似乎是:

  • Typealias (从 java 调用时会很乱)
  • Kotlin 接口(从 kotlin 调用时会很乱,需要创建一个对象)这是一个很大的退步 IMO。
  • Java 接口(从 kotlin 调用时不那么麻烦; lambda 需要预置接口名称,所以不需要对象; 也不能在函数括号约定之外使用 lambda)

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

如果你有这样的 < em > Java 类 :

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

你应该像这样把这段代码从 Java 转换成 科特林:

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 Interface风格:

object : RecyclerTouchListener.ClickListener

试着像这样访问你的界面:

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

如果接口用于类的侦听器方法,则将接口定义更改为函数类型。这使得代码更加简洁。请看下面。

包含侦听器定义的

// 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
}
class YourClass : YourInterface {
override fun getTest() = "test"
}


interface YourInterface {
fun getTest(): String
}


val objectYourClass: YourInterface = YourClass()
print(objectYourClass.getTest())

自从 1.4.0以来,在 Kotlin 定义的接口都支持 SAM 转换

Kotlin 最新消息

在 Kotlin 1.4.0之前,只有在使用来自 Kotlin 的 Java 方法和 Java 接口时,才可以应用 SAM (单一抽象方法)转换。从现在开始,您也可以对 Kotlin 接口使用 SAM 转换。要做到这一点,显式地将 Kotlin 接口标记为带有 fun修饰符的函数。

当只有一个抽象方法的接口作为参数时,如果将 lambda 作为参数传递,那么 SAM 转换将应用。在这种情况下,编译器自动将 lambda 转换为实现抽象成员函数的类的实例。

你的问题中的例子是这样的:

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


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


myObj.onLocationMeasured("New York")
}