Java Kotlin函数参数:如何定义一个可以有一个尾随lambda或接口作为参数的函数?

Java Kotlin函数参数:如何定义一个可以有一个尾随lambda或接口作为参数的函数?,java,android,kotlin,Java,Android,Kotlin,我发现了两个类似的代码: binding.playButton.setOnClickListener ( Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment) ) android视图类中的Java代码: public void setOnClickListener(@Nullable OnClickListener l) { if (!isClick

我发现了两个类似的代码:

binding.playButton.setOnClickListener (
    Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
android视图类中的Java代码:

    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }
问题是:我如何创建这样的函数,在这里我可以使用后面的lambda或interface作为参数? 我发现类型不匹配

    interface One {
        fun a(): Int
    }

    class OneImp : One {
        override fun a(): Int {
            return 4
        }
    }

    fun test(one: One) {
        val a = one
    }

   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
       val a = OneImp()
       test (a)   //works fine
       test {
            a //error
       }
   }

错误:

Type mismatch.
Required:
TitleFragment.One
Found:
() → TitleFragment.OneImp
更新:

在回答了@Jenea Vranceanu之后,我在测试SAM时发现了错误(我使用了kotlin文件中的接口,而所有代码都应该是java)。 解决方案将是:(在kotlinv v1.4发布之前) 创建java文件:

public class Mine {
    public interface One {
        int a();
    }

    public class OneImpl implements One {
        @Override
        public int a() {
            return 4;
        }
    }

    public void test(One one) {}
}
然后我可以使用函数参数和lambda。现在在kotlin文件中:

 Mine().test {4}
 val b = Mine().OneImpl()
 Mine().test (b)

注:如果他将其添加到他的答案中,我将从这里删除If。

您误解了
binding.playButton.setOnClickListener在每种情况下的工作方式

在第一个示例中,
导航
组件创建
视图。OnClickListener
,该视图被传递到
设置OnClickListener
(注意括号或圆括号):

在Java中,它看起来几乎相同:

binding.getPlayButton().setOnClickListener (
    Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
第二个例子的工作原理稍有不同。首先,使用大括号创建
View.OnClickListener
,并定义此
视图的主体。OnClickListener
方法
onClick(视图)

在大括号内有对单击视图的引用:

binding.playButton.setOnClickListener { 
    it.context // `it` is the clicked view
}

// It is the same as
binding.playButton.setOnClickListener { view ->
    view.context
}
为什么它完全不起作用? 这种类型的定义匿名类只能在和
视图中使用。OnClickListener
是Java中定义的SAM类Kotlin SAM类/接口尚不支持此功能。

以书面形式:

val a = OneImp()
test {
    a //error
}
您假设
test
函数声明如下所示:

fun test(one: () -> One) {
    val a = one()
}
请注意,在第二个示例中,问题顶部的
Navigation.findNavController(it.navigate
不会创建
View.OnClickListener
对象大括号创建此对象,由于此接口只有一个抽象方法,因此无法写入此方法签名,因此大括号内声明的所有内容直接进入
void onClick(View View)
方法

更新(正式文件) 。这是官方文件,底部写着:

。。。请注意,此功能仅适用于Java互操作;由于Kotlin具有适当的函数类型,因此不需要将函数自动转换为Kotlin接口的实现,因此不受支持

因此,Kotlin接口永远不支持它,因为不需要它。看来我对“山姆永远不会得到支持”的看法是错误的。这将是,但它还没有提供。Kotlin类的SAM转换将从Kotlin 1.4开始提供,Kotlin 1.4现在是一个候选版本

用解决方案更新 最初未添加替代解决方案。提问者礼貌地要求添加下一个代码以完成回答。谢谢


我已经更新了您的问题标题,使其成为一个问题,如果您对我的更改不满意,请随意编辑:)简单地说,
test{…}
test({…})
相同,lambda作为参数传递,而不是
One
。看,山姆很难理解…:((Kotlin 1.4支持对Kotlin接口进行SAM转换,该版本目前处于候选发布阶段。太好了!感谢您指出这一点。我将更新我的答案。@JeneaVranceanu,感谢您的回答,尽管您没有回答如何做的问题。我在java类中绑定了该转换,但我使用了Kotlin文件中的接口,这是我的问题。)因此,答案将是创建一个新的.java文件,代码为``public class Mine{public interface One{int a();}public class OneImpl实现一个{@Override public int a(){return 4;}}}public void test(One){}```在这之后,IDE提供了lambda提示。请您将其放入您的答案中,使其完整。
binding.playButton.setOnClickListener { 
    it.context // `it` is the clicked view
}

// It is the same as
binding.playButton.setOnClickListener { view ->
    view.context
}
val a = OneImp()
test {
    a //error
}
fun test(one: () -> One) {
    val a = one()
}
public class Mine { 
    public interface One { 
        int a(); 
    } 

    public class OneImpl implements One { 
        @Override public int a() { return 4; } 
    } 
    
    public void test(One one) {} 
}