[Kotlin] Kotlin and Java interoperability② ( @JvmField annotation field to Java | @JvmOverloads annotation modification function | @JvmStatic annotation declares static members )





1. Use the @JvmField annotation to expose Kotlin fields to Java




1. Access Kotlin fields through Getter and Setter methods in Java classes


Fields in Kotlin cannot be accessed directly in Java , and the corresponding Getter and Setter methods must be called to access;


Code example:


Kotlin class: The member properties declared in Kotlin are private private properties by default, and Getter and Setter methods are generated for them by default;

class Hello {
    
    
    var name = "Tom"
}

Direct calls from Java classes: In Java classes, Kotlin fields cannot be called directly;

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        Hello hello = new Hello();
        System.out.println(hello.name);
    }
}

An error will be reported in the Java class:

'name' has private access in 'Hello'

insert image description here


In Java classes, Kotlin fields can only be called through Getter and Setter methods ;

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        Hello hello = new Hello();
        System.out.println(hello.getName());
    }
}

Results of the :
insert image description here


2. Direct access to Kotlin fields decorated with @JvmField annotations in Java classes


If you use the @JvmField annotation to modify member properties in Kotlin , its function is to expose Kotlin fields to Java , and you can directly access Kotlin fields in Java without ;


Kotlin code:

class Hello {
    
    
    @JvmField
    var name = "Tom"
}

Java code:

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        Hello hello = new Hello();
        System.out.println(hello.name);
    }
}

Results of the :

insert image description here

The @JvmField annotation is equivalent to declaring a field in Kotlin as a Java field , at which point Kotlin will not automatically generate Getter and Setter methods for the field;





2. Use the @JvmOverloads annotation to modify the Kotlin function



In Kotlin, function parameters can have their own default values , and you can directly ;

However, when Java calls Kotlin functions , the Java language does not support the syntax of function parameters with default values . If the specified parameters are passed in, the function needs to be overloaded;

Using the @JvmOverloads annotation to modify the Kotlin function in Kotlin will automatically implement a series of overloaded functions for Java users;
for example, if the parameter list is ( String , age ), using the @JvmOverloads annotation to modify the function will automatically generate

  • 0 parameters,
  • 1 parameter,
  • 2 parameters

The function ;


1. Kotlin default parameter function call example


Kotlin code example: In the following helloStudentfunction , both parameters are set with default parameter values . When calling this function in Kotlin, you can pass in 0, 1, and 2 parameters , and you can choose which parameter to pass in if you pass in one parameter ;

class Hello {
    
    
    fun helloStudent(name: String = "Tom", age: Int = 18) {
    
    
        println("Student $name is $age years old , say hello !")
    }
}

fun main() {
    
    
    var hello = Hello();
    hello.helloStudent()
    hello.helloStudent("Jerry")
    hello.helloStudent(age = 22)
    hello.helloStudent("Bill", 12)
}

Results of the :

Student Tom is 18 years old , say hello !
Student Jerry is 18 years old , say hello !
Student Tom is 22 years old , say hello !
Student Bill is 12 years old , say hello !

insert image description here

Analyze the bytecode data of the above Kotlin code , view the bytecode data in Kotlin Bytecode, and decompile it into Java code as follows:

// Hello.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 1,
   d1 = {
    
    "\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001a\u0010\u0003\u001a\u00020\u00042\b\b\u0002\u0010\u0005\u001a\u00020\u00062\b\b\u0002\u0010\u0007\u001a\u00020\b¨\u0006\t"},
   d2 = {
    
    "LHello;", "", "()V", "helloStudent", "", "name", "", "age", "", "KotlinDemo"}
)
public final class Hello {
    
    
   public final void helloStudent(@NotNull String name, int age) {
    
    
      Intrinsics.checkParameterIsNotNull(name, "name");
      String var3 = "Student " + name + " is " + age + " years old , say hello !";
      boolean var4 = false;
      System.out.println(var3);
   }

   // $FF: synthetic method
   public static void helloStudent$default(Hello var0, String var1, int var2, int var3, Object var4) {
    
    
      if ((var3 & 1) != 0) {
    
    
         var1 = "Tom";
      }

      if ((var3 & 2) != 0) {
    
    
         var2 = 18;
      }

      var0.helloStudent(var1, var2);
   }
}
// HelloKt.java
import kotlin.Metadata;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 2,
   d1 = {
    
    "\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
   d2 = {
    
    "main", "", "KotlinDemo"}
)
public final class HelloKt {
    
    
   public static final void main() {
    
    
      Hello hello = new Hello();
      Hello.helloStudent$default(hello, (String)null, 0, 3, (Object)null);
      Hello.helloStudent$default(hello, "Jerry", 0, 2, (Object)null);
      Hello.helloStudent$default(hello, (String)null, 22, 1, (Object)null);
      hello.helloStudent("Bill", 12);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
    
    
      main();
   }
}

2. Call Kotlin default parameter function in Java


If you want to pass in any number and type of parameters in Java code like Kotlin, you need to use function overloading;

If it is called directly like in Kotlin, an error will definitely be reported:
insert image description here

Using the @JvmOverloads annotation to modify the Kotlin function will automatically implement a series of overloaded functions for Java users;


Kotlin code example:

class Hello {
    
    
    @JvmOverloads
    fun helloStudent(name: String = "Tom", age: Int = 18) {
    
    
        println("Student $name is $age years old , say hello !")
    }
}

fun main() {
    
    
    var hello = Hello();
    hello.helloStudent()
    hello.helloStudent("Jerry")
    hello.helloStudent(age = 22)
    hello.helloStudent("Bill", 12)
}

Java code example:

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        Hello hello = new Hello();
        hello.helloStudent();
        hello.helloStudent("Jerry");
        hello.helloStudent("Bill", 12);
    }
}

Results of the :

Student Tom is 18 years old , say hello !
Student Jerry is 18 years old , say hello !
Student Bill is 12 years old , say hello !

insert image description here

Analyze the above bytecode data corresponding to the Kotlin class annotated with @JvmOverloads , and decompile the bytecode back to Java code, the content is as follows:

// Hello.java
import kotlin.Metadata;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 1,
   d1 = {
    
    "\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001c\u0010\u0003\u001a\u00020\u00042\b\b\u0002\u0010\u0005\u001a\u00020\u00062\b\b\u0002\u0010\u0007\u001a\u00020\bH\u0007¨\u0006\t"},
   d2 = {
    
    "LHello;", "", "()V", "helloStudent", "", "name", "", "age", "", "KotlinDemo"}
)
public final class Hello {
    
    
   @JvmOverloads
   public final void helloStudent(@NotNull String name, int age) {
    
    
      Intrinsics.checkParameterIsNotNull(name, "name");
      String var3 = "Student " + name + " is " + age + " years old , say hello !";
      boolean var4 = false;
      System.out.println(var3);
   }

   // $FF: synthetic method
   public static void helloStudent$default(Hello var0, String var1, int var2, int var3, Object var4) {
    
    
      if ((var3 & 1) != 0) {
    
    
         var1 = "Tom";
      }

      if ((var3 & 2) != 0) {
    
    
         var2 = 18;
      }

      var0.helloStudent(var1, var2);
   }

   @JvmOverloads
   public final void helloStudent(@NotNull String name) {
    
    
      helloStudent$default(this, name, 0, 2, (Object)null);
   }

   @JvmOverloads
   public final void helloStudent() {
    
    
      helloStudent$default(this, (String)null, 0, 3, (Object)null);
   }
}
// HelloKt.java
import kotlin.Metadata;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 2,
   d1 = {
    
    "\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
   d2 = {
    
    "main", "", "KotlinDemo"}
)
public final class HelloKt {
    
    
   public static final void main() {
    
    
      Hello hello = new Hello();
      Hello.helloStudent$default(hello, (String)null, 0, 3, (Object)null);
      Hello.helloStudent$default(hello, "Jerry", 0, 2, (Object)null);
      Hello.helloStudent$default(hello, (String)null, 22, 1, (Object)null);
      hello.helloStudent("Bill", 12);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
    
    
      main();
   }
}

After using the @JvmOverloads annotation , overloaded functions with 0, 1, and 2 parameters are automatically generated for the helloStudent function
at compile time , so that these methods can be called directly when called in Java ;

   @JvmOverloads
   public final void helloStudent(@NotNull String name, int age) {
    
    
      Intrinsics.checkParameterIsNotNull(name, "name");
      String var3 = "Student " + name + " is " + age + " years old , say hello !";
      boolean var4 = false;
      System.out.println(var3);
   }

   @JvmOverloads
   public final void helloStudent(@NotNull String name) {
    
    
      helloStudent$default(this, name, 0, 2, (Object)null);
   }

   @JvmOverloads
   public final void helloStudent() {
    
    
      helloStudent$default(this, (String)null, 0, 3, (Object)null);
   }




3. Use the @JvmStatic annotation to declare static members



In Kotlin, there is no concept of static members . When a static member needs to be declared , it is generally declared in its Companion companion object;

When calling members in Kotlin's Companion companion object in Java , you need to call in the following form:

Kotlin.Companion.成员属性
Kotlin.Companion.成员函数

If you want to directly call Companion companion object members in Kotlin without using Companion ,

Can be in companion object ,

Use the @JvmStatic annotation to declare members in the companion object as Java static members,

In Java, it can be accessed as a static member;


1. Java normally accesses Kotlin companion object members


In the following code, to access the members of the Kotlin companion object in the Java language, you need to obtain the companion object of the Hello.Companion class first, and then access the members of the companion object;


Kotlin code:

class Hello {
    
    
    companion object {
    
    
        var name = "Tom"
        fun say() {
    
    
            println("Hello World")
        }
    }
}

Java code:

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(Hello.Companion.getName());
        Hello.Companion.say();
    }
}

Results of the :

Tom
Hello World

insert image description here


View the decompiled Java code of the bytecode generated by this Kotlin class:

import kotlin.Metadata;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 1,
   d1 = {
    
    "\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},
   d2 = {
    
    "LHello;", "", "()V", "Companion", "KotlinDemo"}
)
public final class Hello {
    
    
   @NotNull
   private static String name = "Tom";
   public static final Hello.Companion Companion = new Hello.Companion((DefaultConstructorMarker)null);

   @Metadata(
      mv = {
    
    1, 1, 16},
      bv = {
    
    1, 0, 3},
      k = 1,
      d1 = {
    
    "\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\t\u001a\u00020\nR\u001a\u0010\u0003\u001a\u00020\u0004X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0005\u0010\u0006\"\u0004\b\u0007\u0010\b¨\u0006\u000b"},
      d2 = {
    
    "LHello$Companion;", "", "()V", "name", "", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "say", "", "KotlinDemo"}
   )
   public static final class Companion {
    
    
      @NotNull
      public final String getName() {
    
    
         return Hello.name;
      }

      public final void setName(@NotNull String var1) {
    
    
         Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
         Hello.name = var1;
      }

      public final void say() {
    
    
         String var1 = "Hello World";
         boolean var2 = false;
         System.out.println(var1);
      }

      private Companion() {
    
    
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
    
    
         this();
      }
   }
}

In the bytecode data compiled by Kotlin, the name member attribute and the say member function are defined in the Hello.Companion companion object. If you want to access these two members, you must access them through Hello.Companion;


2. Java statically accesses Kotlin companion object members


In the following code, use the @JvmStatic annotation to modify the members of the companion object in Kotlin, and then these members can be accessed statically in Java;


Kotlin code:

class Hello {
    
    
    companion object {
    
    
        @JvmStatic
        var name = "Tom"

        @JvmStatic
        fun say() {
    
    
            println("Hello World")
        }
    }
}

Java code:

public class HelloJava {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(Hello.getName());
        Hello.say();
    }
}

Results of the :
insert image description here


View the decompiled Java code of the bytecode generated by this Kotlin class:

import kotlin.Metadata;
import kotlin.jvm.JvmStatic;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {
    
    1, 1, 16},
   bv = {
    
    1, 0, 3},
   k = 1,
   d1 = {
    
    "\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},
   d2 = {
    
    "LHello;", "", "()V", "Companion", "KotlinDemo"}
)
public final class Hello {
    
    
   @NotNull
   private static String name = "Tom";
   public static final Hello.Companion Companion = new Hello.Companion((DefaultConstructorMarker)null);

   @NotNull
   public static final String getName() {
    
    
      Hello.Companion var10000 = Companion;
      return name;
   }

   public static final void setName(@NotNull String var0) {
    
    
      Hello.Companion var10000 = Companion;
      name = var0;
   }

   @JvmStatic
   public static final void say() {
    
    
      Companion.say();
   }

   @Metadata(
      mv = {
    
    1, 1, 16},
      bv = {
    
    1, 0, 3},
      k = 1,
      d1 = {
    
    "\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0006\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\n\u001a\u00020\u000bH\u0007R$\u0010\u0003\u001a\u00020\u00048\u0006@\u0006X\u0087\u000e¢\u0006\u0014\n\u0000\u0012\u0004\b\u0005\u0010\u0002\u001a\u0004\b\u0006\u0010\u0007\"\u0004\b\b\u0010\t¨\u0006\f"},
      d2 = {
    
    "LHello$Companion;", "", "()V", "name", "", "name$annotations", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "say", "", "KotlinDemo"}
   )
   public static final class Companion {
    
    
      /** @deprecated */
      // $FF: synthetic method
      @JvmStatic
      public static void name$annotations() {
    
    
      }

      @NotNull
      public final String getName() {
    
    
         return Hello.name;
      }

      public final void setName(@NotNull String var1) {
    
    
         Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
         Hello.name = var1;
      }

      @JvmStatic
      public final void say() {
    
    
         String var1 = "Hello World";
         boolean var2 = false;
         System.out.println(var1);
      }

      private Companion() {
    
    
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
    
    
         this();
      }
   }
}

When the Kotlin class is compiled , it is automatically generated

  • Hello.name static member and its static Getter and Setter methods,
  • Hello. say static method;

These two static members are members of the Hello.Companion companion object in the Kotlin class, but they are generated in the Hello class during compilation and are called members of the Hello class;

public final class Hello {
    
    
   @NotNull
   private static String name = "Tom";

   @NotNull
   public static final String getName() {
    
    
      Hello.Companion var10000 = Companion;
      return name;
   }

   public static final void setName(@NotNull String var0) {
    
    
      Hello.Companion var10000 = Companion;
      name = var0;
   }

   @JvmStatic
   public static final void say() {
    
    
      Companion.say();
   }
}

Guess you like

Origin blog.csdn.net/han1202012/article/details/129109314