Java 为什么这是val,不是val?
这似乎取决于Java和Kotlin之间的交互,首先是Java类:Java 为什么这是val,不是val?,java,kotlin,Java,Kotlin,这似乎取决于Java和Kotlin之间的交互,首先是Java类: public class MyJavaClass { private Runnable q; public void setRunnable(final Runnable listener) { q = listener; } public boolean testContains(final Runnable listener) { return q == li
public class MyJavaClass {
private Runnable q;
public void setRunnable(final Runnable listener) {
q = listener;
}
public boolean testContains(final Runnable listener) {
return q == listener;
}
}
现在Kotlin测试:
class JavaInteractionTests {
@Test
fun `anonymous`() {
val abc = object : Runnable {
override fun run() {
}
}
val x = MyJavaClass()
x.setRunnable(abc)
assertTrue(x.testContains(abc))
}
@Test
fun `lambda`() {
val abc = Runnable { }
val x = MyJavaClass()
x.setRunnable(abc)
assertTrue(x.testContains(abc))
}
@Test
fun `function`() {
val abc: () -> Unit = {}
val x = MyJavaClass()
x.setRunnable(abc)
assertTrue(x.testContains(abc))
}
}
最后一次测试失败,因此看起来我的val
实际上不是val
错误或可解释的预期行为
注意,如果Java类是在Kotlin中定义的,那么最后一个测试不会编译:
class MyKtClass {
private var q: Runnable? = null
fun setRunnable(listener: Runnable) {
q = listener
}
fun testContains(listener: Runnable): Boolean {
return q === listener
}
}
(我在向Java类注册回调时注意到了这一切,稍后将删除它,但未能删除。回调是在第三种测试样式中定义的)原因是,每次调用接受
可运行的
的Java函数并向其中传递Kotlin函数()->单元时,隐式创建了一个Runnable
,用于包装函数
当您这样做两次(x.setRunnable(abc)
和x.testContains(abc)
)时,这是两个不同的Runnable
不相等,因此失败
这就是Kotlin的工作原理。基本上,这些调用相当于
val abc: () -> Unit = {}
val x = MyJavaClass()
x.setRunnable(Runnable(abc)) // one Runnable
assertTrue(x.testContains(Runnable(abc))) // another Runnable
另外,这也是为什么在Kotlin中重新编写类时测试不会编译的原因。理由是Kotlin已经有了功能类型,应该使用它们来代替SAM接口。因此,SAM转换是Java互操作的一种手段,而不是一种完整的语言特性。因为它是一种语言特性。JARSo Kotlin将默默地包装它,但我必须显式地将int转换为long等@韦斯顿,是的,没错。这就是SAM转换在Kotlin中的工作原理(参见我添加的文档链接)。Kotlin如何识别函数是用Java编写的?假设你拉入一个函数采用SAM类型的库。如何决定SAM转换是否编译?@marstran,它不承认它是用Java编写的,它只发现它不是用Kotlin编写的。有两种可能的情况:Kotlin代码属于当前项目时,以及使用Kotlin库时。在第一种情况下,编译器传递的是Kotlin源代码,而不是类,因此它们显然是用Kotlin编写的。在第二种情况下,当您有一个包含类的JAR时,编译器尝试在该JAR中的类中查找Kotlin元数据(反编译一个,您将看到@metadata
注释),如果没有,它认为这些不是Kotlin类。首先,向上投票。这意味着将lambda用于平台SAM类型存在风险?e、 g:subscribe((事件)->Unit)
但我以后不能取消订阅(监听器)
。