Kotlin之@JvmOverloads、@JvmStatic、@JvmField、@JvmInline等注解使用总结

简介: `Kotlin`代码可以经过编译器转换成`VM虚拟机`能识别的字节码,所以`Java`与`Kotlin`可以互相进行调用。而由于`Java`与`Kotlin`语言特性的差异,当`Java`调用`Kotlin`代码时,可以在`Kotlin`代码中适当增加一些注解,从而更方便的调用`Kotlin`代码。

写在前面

Kotlin代码可以经过编译器转换成VM虚拟机能识别的字节码,所以JavaKotlin可以互相进行调用。而由于JavaKotlin语言特性的差异,当Java调用Kotlin代码时,可以在Kotlin代码中适当增加一些注解,从而更方便的调用Kotlin代码。

@JvmOverloads

Kotlin的方法里有多个默认参数时,如果在Java中直接调用,只能调用一个包含完整参数的方法,如果想暴露更多的重载函数给Java,可以使用@JvmOverloads 用于生成重载。对于每一个有默认值的参数,生成的重载会把当前有默认值的参数及其右边的参数都去掉,所以如果方法中所有的参数都有默认值,生成的重载函数中还会有一个无参的重载函数。

@JvmOverloads 主要用于构造函数、方法中,同时不能用于抽象方法、接口中的方法等。

  • 应用在方法中
 @JvmOverloads
 fun method(a: Int, b: Boolean = true, c: String = "c") {
 }

转换成Java后:

   //1
   @JvmOverloads
   public final void method(int a, boolean b, @NotNull String c) {
      Intrinsics.checkNotNullParameter(c, "c");
   }

  //2
   @JvmOverloads
   public final void method(int a, boolean b) {
      method$default(this, a, b, (String)null, 4, (Object)null);
   }

  //3
   @JvmOverloads
   public final void method(int a) {
      method$default(this, a, false, (String)null, 6, (Object)null);
   }

   //4: synthetic method
   public static void method$default(KtAnnotation var0, int var1, boolean var2, String var3, int var4, Object var5) {
      if ((var4 & 2) != 0) {
         var2 = true;
      }
      if ((var4 & 4) != 0) {
         var3 = "c";
      }
      var0.method(var1, var2, var3);
   }
  • 应用在自定义View构造函数中
class VpLoadMoreView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0,
) : LinearLayout(context, attrs, defStyle) {}

转换成Java代码后:

public final class VpLoadMoreView extends LinearLayout {
   
   //1
   @JvmOverloads
   public VpLoadMoreView(@NotNull Context context) {
      this(context, (AttributeSet)null, 0, 6, (DefaultConstructorMarker)null);
   }

   //2
   @JvmOverloads
   public VpLoadMoreView(@NotNull Context context, @Nullable AttributeSet attrs) {
      this(context, attrs, 0, 4, (DefaultConstructorMarker)null);
   }
 
   //3
   @JvmOverloads 
   public VpLoadMoreView(@NotNull Context context, @Nullable AttributeSet attrs, int defStyle) {
      Intrinsics.checkNotNullParameter(context, "context");
      super(context, attrs, defStyle);
   }

   //4: synthetic method
   public VpLoadMoreView(Context var1, AttributeSet var2, int var3, int var4, DefaultConstructorMarker var5) {
      if ((var4 & 2) != 0) {
         var2 = (AttributeSet)null;
      }
      if ((var4 & 4) != 0) {
         var3 = 0;
      }
      this(var1, var2, var3);
   }
}

如果将注解去掉,转换成Java后:

public final class VpLoadMoreView extends LinearLayout {

   //1
   public VpLoadMoreView(@NotNull Context context, @Nullable AttributeSet attrs, int defStyle) {
      Intrinsics.checkNotNullParameter(context, "context");
      super(context, attrs, defStyle);
   }

   //2: synthetic method
   public VpLoadMoreView(Context var1, AttributeSet var2, int var3, int var4, DefaultConstructorMarker var5) {
      if ((var4 & 2) != 0) {
         var2 = (AttributeSet)null;
      }
      if ((var4 & 4) != 0) {
         var3 = 0;
      }
      this(var1, var2, var3);
   }
}

可以看到去掉了@JvmOverloads 注解,少了1个、2个参数的构造函数了,那么在Java中也不能初始化1个、2个参数的构造函数了。

@JvmStatic

@JvmStatic用于声明静态方法。在具名对象及伴生对象中使用时,既会在相应对象的类中生成静态方法,也会在对象自身中生成实例方法,如:

class KtA {
    companion object {
        @JvmStatic
        fun invokeStatic() {}

        fun invokeNoStatic() {}
    }
}

在Java中调用:

 public void invokeKt() {
     KtA.invokeStatic(); //正确,可以直接调用
     //KtA.invokeNoStatic(); //错误,这里调用不到
     KtA.Companion.invokeStatic(); //正确
     KtA.Companion.invokeNoStatic(); //正确
 }

@JvmField

@JvmField使得编译器不再对该字段生成getter/setter并将其作为公开字段,如:

 val id1 = 100 //1
 
 @JvmField 
 val id2 = 200 //2

 var id3 = 300 //3
 
 @JvmField 
 var id4 = 400 //4

编译成Java后:

 private final int id1 = 100;
 @JvmField
 public final int id2 = 200;
 private int id3 = 300;
 @JvmField
 public int id4 = 400;

 public final int getId1() {
    return this.id1;
 }

 public final int getId3() {
    return this.id3;
 }

 public final void setId3(int var1) {
    this.id3 = var1;
 }

@JvmSynthetic

@JvmSynthetic可以修饰于方法上,控制只能在Kotlin中调用,如:

//kt代码
class KtA {
    @JvmSynthetic
    fun visit() {}
}

Java中调用:

 public void invokeKt() {
     KtA clz = new KtA();
     clz.visit(); //错误,这里在Java中调用不到。
 }

如果想在Java中调用到Kotlin类中的方法,将@JvmSynthetic去掉即可。

@JvmName 、@JvmMultifileClass

@JvmName 注解可以生成类名;如果类名已存在,可以修改已生成的 Java 类的类名。
包名相同并且类名相同或者有相同的 @JvmName 注解有会错误,可以通过@JvmMultifileClass把他们合并到一起,如:

//A.kt
@file:JvmName("generate")
@file:JvmMultifileClass
package org.ninetripods
fun getA() {}
//B.kt
@file:JvmName("generate")
@file:JvmMultifileClass
package org.ninetripods
fun getB() {}

Java中调用:

org.ninetripods.generate.getA();
org.ninetripods.generate.getB();

@JvmInline

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@SinceKotlin("1.5")
public actual annotation class JvmInline

@JvmInline1.5.0版本引入,可以指定一个类为内联类,需结合value一起使用;在1.5.0之前使用inline关键字。

//1.5.0之前,inline标记内联类
inline class Person(private val name: String = "")

//1.5.0之后,@JvmInline + value 标记内联类
@JvmInline
value class Person(private val name: String = "")

内联类构造参数中有且只能有一个成员变量,最终被内联到字节码中的value。,上述代码经过内联优化会在字节码中将Person对象转换为String值,从而由堆分配优化为栈分配。

相关文章
|
6月前
|
Kotlin
kotlin获取属性注解
kotlin获取属性注解
67 0
|
10月前
|
Java Kotlin
Kotlin中与Java互操作与可空性、类型映射、属性访问、@JvmOverloads、@JvmField、@JvmStatic、@Throws和函数类型操作详解
Kotlin中与Java互操作与可空性、类型映射、属性访问、@JvmOverloads、@JvmField、@JvmStatic、@Throws和函数类型操作详解
73 0
|
Kotlin
kotlin 中使用 注解处理器的坑
kotlin 中使用 注解处理器的坑
kotlin 中使用 注解处理器的坑
|
Java 编译器 Kotlin
刨下Kotlin | 9. @JvmOverloads 原理 & 一个小细节
刨下Kotlin | 9. @JvmOverloads 原理 & 一个小细节
193 0
|
Kotlin
Kotlin注解处理器
一、如果想要在Kotlin中使用注解处理器,第一步首先要编辑build.gradle 二、点击Gradle中,Tasks中的build,编译项目 三、就会根据需要生产对应目录的源码似的文件 四、好啦,结束了 ...
1039 0
|
23天前
|
安全 Java Android开发
使用Kotlin进行Android应用开发:高效、简洁与乐趣并存
【6月更文挑战第1天】Kotlin,JetBrains开发的静态类型语言,正日益成为Android开发首选。它与Java兼容,提供简洁、安全的语法,如空安全、扩展函数和Lambda表达式,提升开发效率和代码可读性。Kotlin在Android开发中的优势包括提高开发速度、降低学习曲线及强大的社区支持。实践中,数据类简化对象创建,扩展函数增强SDK,Lambda表达式简化回调处理,协程优化异步操作。掌握Kotlin对Android开发者极具价值。
|
24天前
|
存储 安全 Android开发
构建高效的Android应用:Kotlin与Jetpack的结合
【5月更文挑战第31天】 在移动开发的世界中,Android 平台因其开放性和广泛的用户基础而备受开发者青睐。随着技术的进步和用户需求的不断升级,开发一个高效、流畅且易于维护的 Android 应用变得愈发重要。本文将探讨如何通过结合现代编程语言 Kotlin 和 Android Jetpack 组件来提升 Android 应用的性能和可维护性。我们将深入分析 Kotlin 语言的优势,探索 Jetpack 组件的核心功能,并通过实例演示如何在实际项目中应用这些技术。
|
6天前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
15 3
Android面试题之Java 泛型和Kotlin泛型
|
15天前
|
安全 Java Android开发
Kotlin与Java:Android开发的双剑合璧
【6月更文挑战第9天】Kotlin和Java在Android开发中形成互补态势。Java凭借广泛社区支持和丰富的类库资源占据主导,但其语法繁琐和空指针问题限制了发展。Kotlin,设计来解决这些问题,以其简洁、安全、高效的特性逐渐兴起。Kotlin的互操作性允许与Java无缝集成,提升开发效率,减少错误。两者结合提高了代码质量和开发者的灵活性,促进了Android开发社区的繁荣。开发者应把握这种&quot;双剑合璧&quot;,适应技术发展。
30 10
|
8天前
|
Android开发 Kotlin
Android面试题 之 Kotlin DataBinding 图片加载和绑定RecyclerView
本文介绍了如何在Android中使用DataBinding和BindingAdapter。示例展示了如何创建`MyBindingAdapter`,包含一个`setImage`方法来设置ImageView的图片。布局文件使用`&lt;data&gt;`标签定义变量,并通过`app:image`调用BindingAdapter。在Activity中设置变量值传递给Adapter处理。此外,还展示了如何在RecyclerView的Adapter中使用DataBinding,如`MyAdapter`,在子布局`item.xml`中绑定User对象到视图。关注公众号AntDream阅读更多内容。
16 1