前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JvmName 注解在 Kotlin 中的应用

JvmName 注解在 Kotlin 中的应用

作者头像
技术小黑屋
发布2020-01-19 19:00:35
1.8K0
发布2020-01-19 19:00:35
举报
文章被收录于专栏:技术小黑屋技术小黑屋

JvmName注解是Kotlin提供的一个可以变更编译器输出的注解,这里简单的介绍一下其使用规则。

应用在文件上

未应用@JvmName

1 2 3 4 5 6 7 8

package com.example.jvmannotationsample import android.net.Uri fun String.toUri(): Uri { return Uri.parse(this) }

当我们在Java中调用上面的toUri方法时

1

StringExtKt.toUri("https://droidyue.com");

生成的 class 文件名称为

1

./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/StringExtKt.class

应用@JvmName

1 2 3 4 5 6 7 8 9

@file:JvmName("StringUtil") package com.example.jvmannotationsample import android.net.Uri fun String.toUri(): Uri { return Uri.parse(this) }

在Java中调用

1

StringUtil.toUri("https://droidyue.com");

生成的 class 文件名为

1

./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/StringUtil.class

作用在方法上

1 2 3 4 5 6

package com.example.jvmannotationsample.jvm_name @JvmName("isOK") fun String.isValid(): Boolean { return isNotEmpty() }

生成的对应的class 文件,我们可以看到方法名称已经修改了。

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

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/jvm_name/OnMethodSampleKt.class Compiled from "OnMethodSample.kt" public final class com.example.jvmannotationsample.jvm_name.OnMethodSampleKt { public static final boolean isOK(java.lang.String); Code: 0: aload_0 1: ldc #11 // String $this$isValid 3: invokestatic #17 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 6: aload_0 7: checkcast #19 // class java/lang/CharSequence 10: astore_1 11: iconst_0 12: istore_2 13: aload_1 14: invokeinterface #23, 1 // InterfaceMethod java/lang/CharSequence.length:()I 19: ifle 26 22: iconst_1 23: goto 27 26: iconst_0 27: ireturn }

所以,我们在Java代码中,可以这样调用

1 2 3

public static void testJvmNameOnMethod() { OnMethodSampleKt.isOK(""); }

但是,我们在Kotlin代码中,还是只能使用isValid而不是isOK

1 2 3 4

fun testJvmNameOnMethod() { "".isValid() // "".isOK() unresolved reference }

那么问题就奇怪了,生成的class里面的方法是isOK,怎么还能调用isValid呢?

1 2 3 4 5 6 7 8 9 10

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/jvm_name/KotlinPlaygroundKt.class Compiled from "KotlinPlayground.kt" public final class com.example.jvmannotationsample.jvm_name.KotlinPlaygroundKt { public static final void testJvmNameOnMethod(); Code: 0: ldc #8 // String 2: invokestatic #14 // Method com/example/jvmannotationsample/jvm_name/OnMethodSampleKt.isOK:(Ljava/lang/String;)Z 5: pop 6: return }

是的,Kotlin编译器将isValid在字节码层面又替换成了isOK

关于@JvmName作用到方法上,比较好的例子(来自Kotlin官网)是这样的

1 2 3 4 5 6 7

fun List<String>.filterValid(): List<String> { TODO() } fun List<Int>.filterValid(): List<Int> { TODO() }

1 2 3

~/JVMAnnotationSample/app/src/main/java/com/example/jvmannotationsample/jvm_name/GenericList.kt: (3, 1): Platform declaration clash: The following declarations have the same JVM signature (filterValid(Ljava/util/List;)Ljava/util/List;): fun List<Int>.filterValid(): List<Int> defined in com.example.jvmannotationsample.jvm_name in file GenericList.kt fun List<String>.filterValid(): List<String> defined in com.example.jvmannotationsample.jvm_name in file GenericList.kt

上面的两个方法声明会导致Kotlin编译出错,因为

由于JVM对于泛型采取了类型擦除,List<Int>.filterValid()List<String>.filterValid()实际上对应的都是List.filterValid()

所以,对应的解决方法

  • 修改两个的方法名称,比如List<String>.filterValid()修改成List<String>.filterValidString()
  • 第二种就是使用@JvmName达到第一种方法的效果

具体修改如下所示

1 2 3 4 5 6 7 8 9 10 11

package com.example.jvmannotationsample.jvm_name @JvmName("filterValidString") fun List<String>.filterValid(): List<String> { TODO() } @JvmName("filterValidInt") fun List<Int>.filterValid(): List<Int> { TODO() }

作用在属性上

除此之外,@JvmName还可以作用在属性上。比如

1 2 3 4 5

package com.example.jvmannotationsample.jvm_name @get:JvmName("x") @set:JvmName("changeX") var x: Int = 23

在Java中对应的调用

1 2 3 4

public static void testJvmNameOnProperty() { OnPropertiesSampleKt.changeX(111); OnPropertiesSampleKt.x(); }

在Kotlin中对应的调用

1 2 3 4

fun testJvmNameOnProperty() { x = 1111 x }

和作用在方法上一样,其实现原理一致,具体如下面的反编译代码可见一斑。

Java调用处的代码

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/jvm_name/OnPropertiesSampleKt.class Compiled from "OnPropertiesSample.kt" public final class com.example.jvmannotationsample.jvm_name.OnPropertiesSampleKt { public static final int x(); Code: 0: getstatic #11 // Field x:I 3: ireturn public static final void changeX(int); Code: 0: iload_0 1: putstatic #11 // Field x:I 4: return static {}; Code: 0: bipush 23 2: putstatic #11 // Field x:I 5: return }

Kotlin调用处的代码

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

javap -c ./app/build/tmp/kotlin-classes/debug/com/example/jvmannotationsample/jvm_name/KotlinPlaygroundKt.class Compiled from "KotlinPlayground.kt" public final class com.example.jvmannotationsample.jvm_name.KotlinPlaygroundKt { public static final void testJvmNameOnProperty(); Code: 0: sipush 1111 3: invokestatic #36 // Method com/example/jvmannotationsample/jvm_name/OnPropertiesSampleKt.changeX:(I)V 6: invokestatic #40 // Method com/example/jvmannotationsample/jvm_name/OnPropertiesSampleKt.x:()I 9: pop 10: return }

相关文章

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 应用在文件上
    • 未应用@JvmName
      • 应用@JvmName
      • 作用在方法上
      • 作用在属性上
      • 相关文章
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档