kotlin默认参数以及@JvmOverloads

2019-12-26  本文已影响0人  kevinsEegets

kotlin默认参数方法以及@JvmOverloads

我们先来看看java中的构造方法

我们都知道java方法中的参数是必须要传递的

示例代码

 public class TestJava {
    public static void main(String[] args) {
        new Person("");
    }

    static class Person{
        Person(String msg){
            System.out.println("调用了无参的构造函数" + msg);
        }
    }
}

如上代码构造方法需要传递一个参数,那么我们在实例化的时候需要传入

但是kotlin中的参数是可以设置默认值的,设置默认值的参数,调用时如果没有传递就使用设定的默认值

我们首先来看只有一个参数,并且设置了默认的情况

class TestParameter(private val str1: String? = "defaultMsg1"){
    fun printMsg(){
        println("print-->str1---$str1")
    }
}

kotlin调用

   TestParameter().printMsg()

java调用

   new TestParameter().printMsg();

我们通过Kotlin Bttecode看看为什么设置默认参数后我们可以不需要传参

public final class TestParameter {
   private final String str1;

   public final void printMsg() {
      String var1 = "print-->str1---" + this.str1;
      boolean var2 = false;
      System.out.println(var1);
   }

   public TestParameter(@Nullable String str1) {
      this.str1 = str1;
   }

   public TestParameter() {
      this((String)null, 1, (DefaultConstructorMarker)null);
   }
}

看反编译代码后我们不难发现

我们的构造方法被创建了两个,一个是不带参数的,一个是带参数的

我们通过kotlinjava调用时,如没传递参数,其实调用的是TestParameter()无参构造

接着看两个或两个以上的参数,并且有一个被设置默认参数的情况

class TestOneNULLParameter(private val str1: String?, private val str2: String? = "defaultMsg2"){
    fun printMsg(){
        println("print-->str1---$str1---str2---$str2")
    }
}

kotlin调用

    TestOneNULLParameter("msg1").printMsg()

java调用

    new TestOneNULLParameter("msg1","").printMsg();

可以看出,当我们设置了str=“msg2”时,kotlin调用时我们只传递了msg1参数,第二个参数没有传递
java调用时,我们必须要传递两个参数,如果第二个参数没有传递,程序会立马报错,这是为什么呢?我们还是看反编译代码找原因

public final class TestOneNULLParameter {
   private final String str1;
   private final String str2;

   public final void printMsg() {
      String var1 = "print-->str1---" + this.str1 + "---str2---" + this.str2;
      boolean var2 = false;
      System.out.println(var1);
   }

   public TestOneNULLParameter(@Nullable String str1, @Nullable String str2) {
      this.str1 = str1;
      this.str2 = str2;
   }
}

如上代码我们看出,此时我们反编译的代码构造方法只有一个,并且参数是两个str1和‘str2’,那也要就说当我们实例化TestOneNULLParameter时,
我们必须要传递两个参数,Java调用的方式我们理解,Kotlin为什么就只传一个参数也是可以的?我们继续反编译kotlin调用处代码

    (new TestOneNULLParameter("msg1", (String)null, 2, (DefaultConstructorMarker)null)).printMsg();

根据上述反编译调用代码我们知道了原因,原来kotlin在调用时,其实也是传递两个参数的,只不过kotlin默认给我们赋值了一个参数为‘null’

那另外一个问题来了,我们能不能也让用Java调用时默认赋值的参数可以不传递吗?,答案也是可以的,这就得用kotlin的关键字 @JvmOverloads

JvmOverloads

@JvmOverloads注解把多个构造函数合并成一个构造函数
我们用代码解释一下这句话,我们修改一下TestOneNULLParameter代码

    class TestOneNULLJVMOverloadsParameter @JvmOverloads constructor(private val str1: String?, private val str2: String? = "defaultMsg2"){
    fun printMsg(){
        println("print-->str1---$str1---str2---$str2")
    }
}

kotlin调用

     TestOneNULLJVMOverloadsParameter( "msg1").printMsg()

java调用

    new TestOneNULLJVMOverloadsParameter("msg1").printMsg();

这个时候我们发现kotlin和‘java’都可以只传递一个参数了,带有默认参数都被忽略传递了,原因看反编译源码

public final class TestOneNULLJVMOverloadsParameter {
   private final String str1;
   private final String str2;

   public final void printMsg() {
      String var1 = "print-->str1---" + this.str1 + "---str2---" + this.str2;
      boolean var2 = false;
      System.out.println(var1);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1, @Nullable String str2) {
      this.str1 = str1;
      this.str2 = str2;
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1) {
      this(str1, (String)null, 2, (DefaultConstructorMarker)null);
   }
}

如上源码可以清晰的看到,反编译后的代码为我们生成了两个构造,一个参数的就是我们想要的结果,我们现在就可以理解那句话了
@JvmOverloads注解把多个构造函数合并成一个构造函数
还是不太明白,我们让TestOneNULLJVMOverloadsParameter构造方法传递n个参数(都带默认参数),看看会不会生成对应的n+1个对应的构造方法

    class TestOneNULLJVMOverloadsParameter @JvmOverloads constructor(private val str1: String?,private val str2: String?,private val str3: String?, private val str4: String? = "defaultMsg2"){
    fun printMsg(){
        println("print-->str1---$str1---str2---$str2")
    }
}

反编译后代码

    public final class TestOneNULLJVMOverloadsParameter {
   private final String str1;
   private final String str2;
   private final String str3;
   private final String str4;
   private final String str5;

   public final void printMsg() {
      String var1 = "print-->str1---" + this.str1 + "---str2---" + this.str2;
      boolean var2 = false;
      System.out.println(var1);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1, @Nullable String str2, @Nullable String str3, @Nullable String str4, @Nullable String str5) {
      this.str1 = str1;
      this.str2 = str2;
      this.str3 = str3;
      this.str4 = str4;
      this.str5 = str5;
   }
   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1, @Nullable String str2, @Nullable String str3, @Nullable String str4) {
      this(str1, str2, str3, str4, (String)null, 16, (DefaultConstructorMarker)null);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1, @Nullable String str2, @Nullable String str3) {
      this(str1, str2, str3, (String)null, (String)null, 24, (DefaultConstructorMarker)null);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1, @Nullable String str2) {
      this(str1, str2, (String)null, (String)null, (String)null, 28, (DefaultConstructorMarker)null);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter(@Nullable String str1) {
      this(str1, (String)null, (String)null, (String)null, (String)null, 30, (DefaultConstructorMarker)null);
   }

   @JvmOverloads
   public TestOneNULLJVMOverloadsParameter() {
      this((String)null, (String)null, (String)null, (String)null, (String)null, 31, (DefaultConstructorMarker)null);
   }
}

如上代码验证了我们的想法


我们上边的示例代码给构造方法添加@JvmOverloads
如果要给函数添加,其实很简单,我们这里都做一下记录

函数方法重载

  @JvmOverloads
  fun printMsg(){
      println("print-->str1---$str1---str2---$str2")
  }

构造方法重载

  class ClassName @JvmOverloads constructor(private val str1: String?, private val str2: String?){
    fun printMsg(){
        println("print-->str1---$str1---str2---$str2")
    }
}

总结一下:
@JvmOverloads是兼容Java调用Kotlin有默认参数方法的,相对java还是挺方便的

上一篇 下一篇

猜你喜欢

热点阅读