专栏首页技术小黑屋JvmMultifile 注解在 Kotlin 中的应用

JvmMultifile 注解在 Kotlin 中的应用

接触过Kotlin之后,我们会利用其扩展方法特性创建很多便捷的方法来实现更好更快的编码。比如我们对于RxJava进行一些简单的扩展方法实现。

下面的这段代码实现一个将任意的对象转成Single实例

1 2 3 4 5 6 7 8 9 10 11

package com.example.jvmannotationsample import io.reactivex.Single //fileName:SingleExt.kt /** * shortcut method to change T instance into Single<T> instance */ fun <T: Any> T.toSingle(): Single<T> { return Single.just(this) }

接下来的代码,实现将任意类型的List转成Observable实例

1 2 3 4 5 6 7 8 9 10

package com.example.jvmannotationsample import io.reactivex.Observable //fileName:ObservableExt.kt /** * shortcut method to convert List<T> instance to Observable<List<T>> instance */ fun <T: Any> List<T>.toObservable(): Observable<List<T>> { return Observable.fromArray(this) }

针对上面的代码,我们使用时会是下面的样子

1 2 3

//the old way SingleExtKt.toSingle("Kotlin"); ObservableExtKt.toObservable(Arrays.asList("Kotlinc", "Developer", "Friends"));

能不能将上面两个类合成一个呢

有时候,我们可能处于这样的考虑,比如SingleExt与ObservableExt里面的扩展方法都是和RxJava有关,可不可以同一称为RxUtil呢,这样使用起来也很方面。

答案是,可以的,就是利用@file:JvmName和@file:JvmMultifileClass就可以实现。

实现代码如下

1 2 3 4 5 6 7 8 9 10 11 12

@file:JvmName("RxUtil") @file:JvmMultifileClass package com.example.jvmannotationsample import io.reactivex.Single //fileName:SingleExt.kt /** * shortcut method to change T instance into Single<T> instance */ fun <T: Any> T.toSingle(): Single<T> { return Single.just(this) }

1 2 3 4 5 6 7 8 9 10 11 12

@file:JvmName("RxUtil") @file:JvmMultifileClass package com.example.jvmannotationsample import io.reactivex.Observable //fileName:ObservableExt.kt /** * shortcut method to convert List<T> instance to Observable<List<T>> instance */ fun <T: Any> List<T>.toObservable(): Observable<List<T>> { return Observable.fromArray(this) }

修改后,就可以在Java中完全使用RxUtil调用了。

1 2 3

//a much better way using @file:JvmMultifileClass RxUtil.toSingle("Kotlin"); RxUtil.toObservable(Arrays.asList("Kotlinc", "Developer", "Friends"));

内部机制

确实有一些神奇,简简单单的增加几个注解,就能实现。但是这样远远还不够,我们需要了解它是如何工作的。

查找对应的类

1 2 3 4

find . -name "*.class" ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil.class ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil__ObservableExtKt.class ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil__SingleExtKt.class

使用javap工具拆解分析RxUtil.class文件

1 2 3 4 5 6 7 8 9 10 11 12 13 14

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil.class public final class com.example.jvmannotationsample.RxUtil { public static final <T> io.reactivex.Observable<java.util.List<T>> toObservable(java.util.List<? extends T>); Code: 0: aload_0 1: invokestatic #12 // Method com/example/jvmannotationsample/RxUtil__ObservableExtKt.toObservable:(Ljava/util/List;)Lio/reactivex/Observable; 4: areturn public static final <T> io.reactivex.Single<T> toSingle(T); Code: 0: aload_0 1: invokestatic #21 // Method com/example/jvmannotationsample/RxUtil__SingleExtKt.toSingle:(Ljava/lang/Object;)Lio/reactivex/Single; 4: areturn }

上面的代码,我们可以看到

  • toObservable方法内部实际上是调用了RxUtil__ObservableExtKt.toObservable
  • toSingle 方法内部实际上是调用了RxUtil__SingleExtKt.toSingle

下面是对两个具体实现类的分析。

使用javap工具拆解分析RxUtil__ObservableExtKt.class文件

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil__ObservableExtKt.class Compiled from "ObservableExt.kt" final class com.example.jvmannotationsample.RxUtil__ObservableExtKt { public static final <T> io.reactivex.Observable<java.util.List<T>> toObservable(java.util.List<? extends T>); Code: 0: aload_0 1: ldc #10 // String $this$toObservable 3: invokestatic #16 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 6: iconst_1 7: anewarray #18 // class java/util/List 10: dup 11: iconst_0 12: aload_0 13: aastore 14: invokestatic #24 // Method io/reactivex/Observable.fromArray:([Ljava/lang/Object;)Lio/reactivex/Observable; 17: dup 18: ldc #26 // String Observable.fromArray(this) 20: invokestatic #29 // Method kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 23: areturn }

使用javap工具拆解分析RxUtil__SingleExtKt.class文件

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil__SingleExtKt Warning: Binary file ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/RxUtil__SingleExtKt contains com.example.jvmannotationsample.RxUtil__SingleExtKt Compiled from "SingleExt.kt" final class com.example.jvmannotationsample.RxUtil__SingleExtKt { public static final <T> io.reactivex.Single<T> toSingle(T); Code: 0: aload_0 1: ldc #10 // String $this$toSingle 3: invokestatic #16 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 6: aload_0 7: invokestatic #21 // Method io/reactivex/Single.just:(Ljava/lang/Object;)Lio/reactivex/Single; 10: dup 11: ldc #23 // String Single.just(this) 13: invokestatic #26 // Method kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 16: areturn }

相关Kotlin内容推荐

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 检查Android是否具有摄像头

    通常我们进行摄像头操作,如扫描二维码需要判断是否有后置摄像头(Rear camera),比如Nexus 7 一代就没有后置摄像头,这样在尝试使用的时候,我们需要...

    技术小黑屋
  • Android中HTTP相关的API

    Android中大多数应用都会发送和接受HTTP请求,在Android API中主要由两个HTTP请求的相关类,一个是HttpURLConnection,另一个...

    技术小黑屋
  • Android根据资源名获取资源ID

    接触过Android开发的同学们都知道在Android中访问程序资源基本都是通过资源ID来访问。这样开发起来很简单,并且可以不去考虑各种分辨率,语言等不同资源显...

    技术小黑屋
  • 首届腾讯运维技术开放日!对外报名正式启动!

    ? 服务不停歇,运维不休息。 运维的工作长达7*24 小时,故而每年的 7月24日被视为运维日,代表着运维全天候的保障系统稳定、维护业务正常运行、时刻准备着...

    腾讯技术工程官方号
  • 大数据如何助力新零售起飞,把商业机密讲给你听!

    世界上有千千万万种的零售企业,它们的商业模式各不相同,有的持续赚钱增长,有的却亏损倒闭。那么,零售行业如何赚钱,它们的底层逻辑是什么,大数据又如何助力新零售,今...

    木东居士
  • ​深圳 | 首届腾讯运维技术开放日,为你而来

    7x24 小时连轴转已成为运维工程师的常态,故而每年的 7 月 24 日被视为运维日,代表着运维全天候的保障系统稳定、维护业务正常运行、时刻准备着一线工作的召唤...

    CODING研发管理系统
  • SpringBoot 中的服务端消息推送

    在SpringBoot中需要注意的是,如果你是以jar包运行,则需要手动的在容器中注入ServerEndpointExporter这个Bean(不进行加载,则连...

    好好学java
  • 《vi和vim》 学习手记(2)

    :set wm=10 设置与右边界的距离。右边界为10个字符。 o 移到一行的开头 s 移到一行的结尾 w 移到下一个单词的 b 退后一个单词 S 更改一行文本...

    用户1154259
  • 腾讯DevOps全链路解决方案

    织云平台团队
  • ceph运维常用命令

    ceph osd df - 可以查看每个osd的用量,每个osd的pg数,权重 ceph osd find <int> - 可以查找到osd的位置,在osd比较...

    院长技术

扫码关注云+社区

领取腾讯云代金券