了解 Java 如何一次调用 Kotlin 的高级功能
我报名了Goldstone Project Phase 1 Challenge——瓜分100,000奖池,这是我的第4篇文章, 点击查看活动详情
Java 如何调用 Kotlin
前言
虽然 Kotlin 已经推出多年,但在中国的火爆程度并不算高,使用 Java 语言开发的新老项目依然不少。 (Java 从来都不是奴隶)
如果项目中其他小伙伴用的是Kotlin,而我只懂Java,那怎么调用他的Kotlin方法呢?事实上,Kotlin 已经为我们做了兼容性,很多特性我们可以用 Java 来调用。
下面我们来看看一些常用的 Kotlin 特性是如何使用 Java 语言来调用的。
1、Java调用KT属性和方法
Kotlin 的属性和方法是在 Java 中调用的。这个大家应该都知道吧,简单说一下吧。
我们在 Kotlin 类中定义了一些基本的方法和变量:
类 KotlinDemo {
变量名称:字符串 = “newki”
有趣的 printName () {
YYLogUtils.w("名称:$name")
}
验证年龄:诠释
得到() {
返回 28
}
}
复制代码
取出方法:
如何使用:
KotlinDemo 演示 = new KotlinDemo();
演示.getAge();
demo.setName("123");
演示.getName();
复制代码
二、Java调用KT静态属性和方法
对于静态属性和方法,我们需要注意注解的使用。
我们在 Kotlin 类中定义了一些静态方法和变量:
类 KotlinDemo {
伴随对象{
var school: String = "武汉学"
@JvmField
var行业:字符串=“IT”
有趣的 callStaticMethod1 () {
YYLogUtils.w("调用静态方法")
}
@JvmStatic
有趣的 callStaticMethod2 () {
YYLogUtils.w("调用静态方法")
}
}
}
复制代码
取出方法:
具体用途:
KotlinDemo.Companion.callStaticMethod1();
KotlinDemo.callStaticMethod2();
KotlinDemo.Companion.getSchool();
KotlinDemo.Companion.setSchool("11");
KotlinDemo.industry = "xx";
复制代码
3、Java调用KT顶层函数/扩展函数
Kotlin 的顶级函数或扩展函数可以通过在函数的类名后面加上后缀 kt 来直接调用。可以调用默认的扩展函数。需要注意的是,需要一些添加泛型的方法。
例如,在我们的 Kotlin 类中定义的顶级函数
有趣的 topLevelFun () {
YYLogUtils.w("调用顶层函数")
}
复制代码
我们在基类中定义的一些扩展函数:
CommonExt.kt:
有趣的上下文。 dp2px (dpValue: Float): Int {
return (dpValue * resources.displayMetrics.density + 0.5f).toInt()
}
复制代码
ActivityExt.kt:
inline fun <reified T> 上下文。 gotoActivity ( 标志: Int = -1 , bundle: Array < out Pair < String , Any?>>? = null ) {
val intent = Intent(this, T:: class.java).apply {
如果(标志!= - 1){
this.addFlags(标志)
}
如果(这!是活动){
this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
如果(捆绑!= null){
putExtras(bundle.toBundle()!!)
}
}
开始活动(意图)
}
复制代码
我们一些可用的扩展功能和一些不可用的扩展功能:
可以看出ActivityExt类中的一些扩展函数是不能使用的。一些带注释的泛型的内联函数+扩展方法确实不可用。 (我还是用错了?不知道有没有大佬指点一下!)
四、Java调用KT高阶函数
高阶函数是可以作为参数方法的函数,比如最简单的高阶函数对象 () -> 单位
这种函数在转换成Java的过程中会生成相应的Function接口。我们可以直接创建 new Function 的匿名接口对象。
比如我们如何定义一些高级函数:
类 KotlinDemo {
有趣的字符串。 setValueCallback (block: () -> Unit) {
堵塞()
}
有趣的 setValueCallback2 (block: () -> Unit , action: ( Int ) -> Int ) {
堵塞()
val action1 = action(1)
YYLogUtils.w("我收到了处理后的值-计算结果:$action1")
}
}
复制代码
那么如何在 Java 中调用它呢?
公共无效演示2(查看视图){
KotlinDemo 演示 = new KotlinDemo();
demo.setValueCallback("str", new Function0<Unit> () {
@覆盖
公共单元调用(){
ToastUtils.INSTANCE.makeText(mActivity, "我被召回了!!");
返回空值;
}
});
demo.setValueCallback2(新功能0<Unit> () {
@覆盖
公共单元调用(){
YYLogUtils.w("这里没有返回值,我只是回调给我");
返回空值;
}
},新功能1<Integer, Integer> () {
@覆盖
公共整数调用(整数整数){
YYLogUtils.w("这里有返回值,回调在这里,我还需要处理操作,我的上级可以收到我处理的值");
返回整数 + 10;
}
});
}
复制代码
打印结果:
高阶函数的Java调用可以说是后续的基础。关于 Function 的接口,Kotlin 为我们定义了从 Function1 到 Function22 的 20 多个接口对象,它们只是用来区分有多少个参数,本质是一样的。
没有人真正定义这么多参数,我最多使用三个参数
5、Java调用KT的SAM方法
实际上,Sam 是基于 Kotlin 的一种简化方法。 Java调用Kotlin其实是一样的。它只适用于 Kotlin。
例如:
接口 MyCustomCallback {
有趣的回调()
}
复制代码 有趣的界面 MyCustomCallback {
有趣的回调()
}
复制代码 有趣的 setSamMethod(回调:MyCustomCallback){
回调.onCallback()
}
复制代码
在 Java 中是相同的调用
public void demo5(查看视图){
KotlinDemo 演示 = new KotlinDemo();
demo.setSamMethod(新的 MyCustomCallback(){
@覆盖
公共无效onCallback(){
YYLogUtils.w("回调");
}
});
}
复制代码
这只是 Kotlin 语言的另一种新方式:
有趣的 setValueCallback2 (block: MyCustomCallback .() -> Unit ) {
块(对象:MyCustomCallback {
覆盖有趣的 onCallback () {
YYLogUtils.w("对方打来电话,然后我继续执行")
}
})
}
复制代码 有趣的 setValueCallback2 (block: MyCustomCallback .() -> Unit ) {
block(MyCustomCallback { YYLogUtils.w("对方打电话,然后我继续执行") })
}
复制代码
其实和高阶函数的调用类似,只不过一个是我们自己定义的接口,一个是Java转换的高阶函数的Function接口,在使用上是一样的。
6、Java调用KT高阶扩展函数
什么是高级扩展函数,其实就是高级函数,只不过把原来回调的对象类型放在了前面,用扩展的方式表达。 以扩展的方式定义高阶函数 ,我称其为高阶扩展函数,但其本质还是高阶函数。
举一个非常简单的例子
有趣的字符串。 setValueCallback11 (block: Industry .( Int ) -> Unit ) {
块(行业(0,这个,“123”,“456”),10)
}
有趣的字符串。 setValueCallback12 (block: ( Industry , Int ) -> Unit ) {
块(行业(0,这个,“123”,“456”),10)
}
复制代码
前者是高阶扩展函数,后者是高阶函数。用法同理,只是高阶函数回调时,需要由它或指定的变量接收,而高阶扩展函数只需要由this接收,更高阶的-order 扩展函数只需要被 this 接收。扩展函数默认为回调的第一个参数。
例如:
“测试”.setValueCallback11 { int ->
YYLogUtils.w("收到回调:行业:" + this.toString() + "int:" + int)
}
“测试”.setValueCallback12 {行业,int->
YYLogUtils.w("收到回调:行业:"+行业.toString()+"int:"+int)
}
复制代码
一个直接使用这个,另一个需要使用它或自定义名称来接收。用起来是一样的,但是如果用高阶扩展函数的话,会有一些简写的方法,比较方便,(不懂的可能会比较混乱)
如何定义高阶扩展函数
这种方式有几种定义方式,函数类型定义为扩展函数定义和非扩展函数定义。参数分为基本类型、自定义类型和接口类型。
下面我就从简单常用的说起。
基本数据类型:
// 这个比较常见
有趣的字符串。 setValueCallback (block: String .() -> Unit ) {
块(this.length.toString())
}
复制代码 demo.setValueCallback("test", new Function1<String, Unit> () {
@覆盖
公共单元调用(字符串 s){
YYLogUtils.w("看看我得到了什么:" + s);
返回空值;
}
});
复制代码
使用扩展方法加上高阶扩展函数的参数,我们可以直接使用this。可以直接获取数据设置回调。
该方法主要用于 直接回拨给对方
打印结果:
自定义对象类型:
如果我们修改高阶扩展函数的对象,可以看到这是不协调的。 String 的扩展方法确实是 Industry 对象的回调。
有趣的字符串。 setValueCallback (block: Industry .() -> Unit) {
// 直接回调对方
块(this.length.toString())
}
复制代码
如果仍然使用String参数,上面的用法会报错,我们应该回调Industry对象。
有趣的字符串。 setValueCallback (block: Industry .() -> Unit) {
// 直接回调对方
块(行业(0,这个,“123”,“456”))
}
复制代码
我们把String的扩展this作为Industry的构造参数的一个属性,这样我们就可以回调一个Industry对象给Java
看Log打印,回调是Industry
接口类型:
除了将对象作为高阶扩展函数外,我们还可以通过接口的形式来做高阶扩展函数。
//也可以设置不相关的对象扩展
有趣的 setValueCallback2 (block: MyCustomCallback .() -> Unit ) {
块(对象:MyCustomCallback {
覆盖有趣的 onCallback () {
}
})
}
复制代码
使用接口类型扩展我的参数,这里我们需要给调用者新建一个对象。这导致这种方法是 回拨给对方,然后通过对方回拨给自己
在Java代码中,我们可以直接调用接口的方法,让对方执行。
public void demo3(查看视图){
KotlinDemo 演示 = new KotlinDemo();
demo.setValueCallback2(新函数1<MyCustomCallback, Unit> () {
@覆盖
公共单元调用(MyCustomCallback myCustomCallback){
//转移
myCustomCallback.onCallback();
返回空值;
}
});
}
复制代码
打印出来的Log如下:
不管是Java代码调用还是Ktolin代码调用,本质都是一样的。
需要注意的是方法的参数是基本类型的高阶扩展函数,对象类型的高阶扩展函数,还是接口类型的高阶扩展函数。这导致了不同的回调方式。
方法本身是否是扩展函数相对不重要。主要是看我们能不能用这个方便。如果我们需要这个对象,我们可以使用扩展功能。如果我们不需要它,我们可以使用它。
高阶扩展函数的补充
其实前面说了,本质还是一个高级扩展函数,只是为了区分是否使用this来接收,所以高级扩展函数也是针对Kotlin的,而针对Java语言,还是处理的作为高级功能。
例如:
有趣的字符串。 setValueCallback1 (block: String .( Int ) -> Unit ) {
块(这个,10)
}
复制代码
Java代码中使用了这种高阶扩展函数:
KotlinDemoKt.setValueCallback1("test", new Function2<String, Integer, Unit> () {
@覆盖
公共单元调用(字符串s,整数整数){
YYLogUtils.w("收到回调:s:" + s + "integer:" + integer);
返回空值;
}
});
复制代码
可以看出Java语言可以扩展也可以不扩展,它只有两个参数,我不能用这个什么的,只能用转换后的Function。可以看出,虽然Kotlin定义了Int,但是Java接收到的是Function2是一个有两个参数的回调,顺序是第一个是String,第二个是Int。
上面提到的基本类型、对象类型、接口类型,这里有完整的demo
有趣的字符串。 setValueCallback0 (block: ( Int ) -> Unit ) {
块(10)
}
有趣的字符串。 setValueCallback1 (block: String .( Int ) -> Unit ) {
块(这个,10)
}
有趣的字符串。 setValueCallback11 (block: Industry .( Int ) -> Unit ) {
块(行业(0,这个,“123”,“456”),10)
}
有趣的字符串。 setValueCallback12 (block: ( Industry , Int ) -> Unit ) {
块(行业(0,这个,“123”,“456”),10)
}
有趣的字符串。 setValueCallback13 (block: MyCustomCallback .( String ) -> Unit ) {
block(MyCustomCallback { YYLogUtils.w("对方打来了,然后我继续执行") }, this + "dot suffix")
}
复制代码
为了便于理解,我在回拨的时候特意没有省略这个。一般大家在写代码的时候都会省略这个。
如果用 Kotlin 代码调用,就很简单了
“测试”.setValueCallback1 { int ->
YYLogUtils.w("收到回调:str:" + this + "int:" + int)
}
“测试”.setValueCallback11 { int ->
YYLogUtils.w("收到回调:行业:" + this.toString() + "int:" + int)
}
“测试”.setValueCallback12 {行业,int->
YYLogUtils.w("收到回调:行业:"+行业.toString()+"int:"+int)
}
“测试”.setValueCallback13 { str ->
YYLogUtils.w("收到回调:回调:" + this + "str:" + str)
this.onCallback()
}
复制代码
它打印如下:
如果它是由 Java 代码调用的:
公共无效演示2(查看视图){
KotlinDemo 演示 = new KotlinDemo();
KotlinDemoKt.setValueCallback1("test", new Function2<String, Integer, Unit> () {
@覆盖
公共单元调用(字符串s,整数整数){
YYLogUtils.w("收到回调:s:" + s + "integer:" + integer);
返回空值;
}
});
KotlinDemoKt.setValueCallback11("test", new Function2<Industry, Integer, Unit> () {
@覆盖
公共单位调用(行业行业,整数整数){
YYLogUtils.w("收到回调:行业:" + this.toString() + "integer:" + integer);
返回空值;
}
});
KotlinDemoKt.setValueCallback12("test", new Function2<Industry, Integer, Unit> () {
@覆盖
公共单位调用(行业行业,整数整数){
YYLogUtils.w("收到回调:行业:" + this.toString() + "integer:" + integer);
返回空值;
}
});
KotlinDemoKt.setValueCallback13("test", new Function2<MyCustomCallback, String, Unit> () {
@覆盖
公共单元调用(MyCustomCallback myCustomCallback,String s){
YYLogUtils.w("收到回调:回调:" + myCustomCallback.toString() + "str:" + s);
myCustomCallback.onCallback();
返回空值;
}
});
复制代码
可以看出,这种方法对Java没有影响,和使用高阶函数完全一样。
打印日志如下:
结论:这个高阶函数定义的扩展函数对Java调用没有影响,只是对Kotin语言的一种简化。
七、Java调用KT的DSL方法
循序渐进,我们会知道Java调用扩展函数和高阶扩展函数,然后在此基础上就可以完成Kotlin DSL调用了。
我们都知道,DSL的简化规则是基于高阶扩展函数间接实现的(也可以直接用高阶函数实现,但是在使用的时候需要用它来指出方法,也就是不优雅,所以一般大家都使用高阶扩展函数的方式来实现)。
所以在我们学习了如何在Java中调用高阶扩展函数之后,让我们回过头来看看DSL调用有什么不同。
前面的文章已经讲过DSL定义的几种方式。这里的BB不多,让我们快速过一遍代码:
有趣的测试网。 setOnSuccessCallbackDsl ( 初始化 : SuccessCallbackImpl .() -> Unit ) {
val listener = SuccessCallbackImpl()
初始化(监听器)
this.setOnSuccessCallback(监听器)
}
var mCallback: SuccessCallback? =空
有趣的 setOnSuccessCallback (回调: SuccessCallback ) {
this.mCallback = 回调
}
interface SuccessCallback { //多个参数不能用fun修改
有趣的 onSuccess (str: String): String
有趣的 doSth()
}
类 SuccessCallbackImpl : TestNet.SuccessCallback {
私有 var onSuccess: ((String) -> String)? =空
private var doSth: (() -> Unit)? =空
有趣的成功(方法:(字符串)->字符串){
onSuccess = 方法
}
有趣的doSth(方法:()->单位){
doSth = 方法
}
覆盖有趣的 onSuccess (str: String): String {
返回 onSuccess?.invoke(str).toString()
}
覆盖乐趣doSth(){
doSth?.invoke()
}
}
复制代码
我们定义一个测试方法来回调数据
有趣的 requestDSLCallback () {
MainScope().launch {
val 结果 = withContext(Dispatchers.IO) {
延迟(500)
返回@withContext Random().nextInt(10)
}
val res = mCallback?.onSuccess("DSL 测试 --> 成功")
YYLogUtils.w("结果:$res")
mCallback?.doSth()
}
}
复制代码
Kotlin 代码使用 DSL,相信大家都很熟悉。
val testNet = TestNet()
testNet.setOnSuccessCallbackDsl {
onSuccess { str ->
YYLogUtils.w("str: $str")
str + "添加更多数据"
}
做事{
YYLogUtils.w("成功后可以写任何逻辑")
}
}
testNet.requestDSLCallback()
复制代码
打印日志:
重点是如何在Java中以这种方式调用DSL?我们了解到Java调用扩展方法,Java调用高阶扩展函数,所以组合是这样的:
测试网 testNet = new TestNet();
TestNetKt.setOnSuccessCallbackDsl(testNet, new Function1<SuccessCallbackImpl, Unit> () {
@覆盖
公共单元调用(SuccessCallbackImpl successCallback){
successCallback.onSuccess(新函数1<String, String> () {
@覆盖
公共字符串调用(字符串 s){
YYLogUtils.w("str:" + s);
return s + "添加一点数据 2";
}
});
successCallback.doSth(新函数0<Unit> () {
@覆盖
公共单元调用(){
YYLogUtils.w("成功后你可以写任何你想要的逻辑2");
返回空值;
}
});
返回空值;
}
});
testNet.requestDSLCallback();
复制代码
我们需要在回调方法中使用接口对象,手动实现回调方法,回调的具体方法是扩展函数的Java转换函数Function接口。
这样就可以实现Kotlin的DSL调用了,打印出来的Log如下:
看起来比较麻烦,但仔细一看,其实是同一套Java调用高阶函数,不过Kotlin语言使用的是高阶扩展函数,看起来更简洁。
八、Java调用KT协程
事实上,我们不能在Java代码中使用协程或者使用协程不方便,但是在我们介绍了上面的解决方案之后,我们可以间接实现协程。
比如我们使用一个Kotlin工具类作为中间层,然后我们就可以启动协程,通过回调方法切换协程的运行。虽然比较麻烦,但毕竟可以用!
我们在 Kotlin 代码中定义协程
//协程
fun setValueCallback3 (block: CoroutineScope .() -> Unit) {
GlobalScope.launch(Dispatchers.IO) {
块(这个)
}
}
复制代码
不用说,如果是在 Kotlin 代码中,那一定很简单
KotlinDemo().setValueCallback3 {
YYLogUtils.w("在协程中执行?"+Thread.currentThread().name)
}
复制代码
跑:
但是我们如何在 Java 代码中运行它呢? Kotlin 代码中默认使用的高阶函数是 {},而在 Java 代码中,它帮助我们将其转换为 Function 接口,相当于上面高阶扩展函数的用法。
公共无效演示4(查看视图){
KotlinDemo 演示 = new KotlinDemo();
demo.setValueCallback3(新函数1<CoroutineScope, Unit> () {
@覆盖
公共单元调用(CoroutineScope coroutineScope){
YYLogUtils.w("在协程中执行?" + Thread.currentThread().getName());
返回空值;
}
});
}
复制代码
跑:
如果要指定挂起标志,还可以
fun setValueCallback4 (block: suspend CoroutineScope .() -> Unit ) {
GlobalScope.launch(Dispatchers.IO) {
block.invoke(这个)
}
}
复制代码
使用方法是一样的:
demo.setValueCallback4(新函数2 <CoroutineScope, Continuation<? super Unit> , 对象>() {
@覆盖
公共对象调用(CoroutineScope coroutineScope,Continuation<? super Unit>继续){
YYLogUtils.w("在协程中执行挂起?" + Thread.currentThread().getName());
返回空值;
}
});
复制代码
说到这里,我给大家解释一个小细节。需要注意的是,Kotlin 代码中的回调是写的。
//协程
fun setValueCallback3 (block: CoroutineScope .() -> Unit) {
GlobalScope.launch(Dispatchers.IO) {
块(这个)
}
}
复制代码
上一篇文章讲了一些高级扩展函数的缩写。注意这里其实有很多种写回调调用的方法,但都是缩写。标准回调是:
块(这个)
一些缩写使用
堵塞()
堵塞
其实并没有错,只是简写而已,但是,在Kotlin语言中调用它并没有错,但是在Java语言中不会有回调。
所以如果你看到别人的代码使用默认的block(this)回调进行一些高阶扩展函数回调,那可能不是因为别人不知道一些缩写。也许其他人想适应 Java 的调用?
实际上,建议您使用标准回调 block(this) 或 block.invoke(this)。这样,函数调用和内部参数更规范,更简单,更清晰,适应性更好。
接下来,我们继续启动协程,更复杂地切换协程。
(PS:我真的不想再写了,真的有什么冤枉会用Java写协程吗……)
简单来说,我们使用一个中间层,在 Kotlin 工具类中定义一些协程的使用,然后通过高阶函数,或者高阶扩展函数回调。
fun callLaunch (block: suspend CoroutineScope .() -> Unit ) {
GlobalScope.launch(Dispatchers.Main) {
block.invoke(这个)
}
}
暂停有趣的 callWithContext (block: () -> String): String {
返回 withContext(Dispatchers.IO) {
堵塞()
}
}
复制代码
使用时:
demo.callLaunch(新功能2 <CoroutineScope, Continuation<? super Unit> , 对象>() {
@覆盖
公共对象调用(CoroutineScope coroutineScope,Continuation<? super Unit>继续){
YYLogUtils.w("启动协程 ===> 做点好事" + Thread.currentThread().getName());
demo.callWithContext(新函数0<String> () {
@覆盖
公共字符串调用(){
YYLogUtils.w("切换线程查看" + Thread.currentThread().getName());
返回空值;
}
},新的延续<String>() {
@NonNull
@覆盖
公共协程上下文 getContext () {
返回 coroutineScope.getCoroutineContext();
}
@覆盖
public void resumeWith (@NonNull Object o) {
}
});
返回空值;
}
});
复制代码
打印结果:
总的来说,在 Java 中使用协程确实是一种折磨,即使使用回调进行间接调用也是一种折磨,并且必须自己手动管理协程上下文。终极折磨!
总结
一般来说,Java调用Kotlin时,协程不好用,扩展函数中不能使用内联泛型。我们可以通过其他方式通过 Java 调用 Kotlin 代码。
因此,Kotlin 的一些特性可以和 Kotlin 一样使用。虽然从 Java 调用 Kotlin 很麻烦,而且一点都不优雅,但毕竟可以用。你想要什么样的自行车?
话虽如此,我还是推荐大家学习 Kotlin,使用 Kotlin 构建项目。毕竟,稍微回顾一下,Compose 必然会成为一种趋势……
好吧,话说回来,Java 调用 Kotlin 是我平时的一些项目,闭门造车在所难免。如果你有更好的方法,可以在评论区讨论。
好了,这篇文章的所有代码和Demo都已经开源了。有兴趣看看 这里 .项目会持续更新,大家可以关注。
如果解释不到位或有错误,希望同学们也可以指出交流。
如果你觉得这篇文章对你有一点启发,希望你能 喜欢
支持,您的支持是我最大的动力。
好了,本期到此结束。
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。
这篇文章的链接: https://homecpp.art/2525/10633/1125
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明