注解JvmOverloads的原理

1,898 阅读2分钟

查看源码

JvmOverloads这个注解对我们来说很熟悉,平常自定义view的时候,就经常用到,它可以方便的实现重载函数的效果,怎么实现的呢,以一个具体的例子来看:

@JvmOverloads

fun overloadFun(name: String, age: Int, height: Int = 0, width: Int = 0) {}

我们定义了一个overloadFun的函数,里面有四个参数,其中后两个有默认值,那么经过编译后,就会生成两个重载函数,我们反编译一下

@JvmOverloads

public final void overloadFun(@NotNull String name, int age, int height) {

   overloadFun$default(this, name, age, height, 0, 8, (Object)null);

}



@JvmOverloads

public final void overloadFun(@NotNull String name, int age) {

   overloadFun$default(this, name, age, 0, 0, 12, (Object)null);

}



// $FF: synthetic method

public static void overloadFun$default(ImageTemplateDelegateV2 var0, String var1, int var2, int var3, int var4, int var5, Object var6) {

   if ((var5 & 4) != 0) {

      var3 = 0;

   }



   if ((var5 & 8) != 0) {

      var4 = 0;

   }



   var0.overloadFun(var1, var2, var3, var4);

}



@JvmOverloads

public final void overloadFun(@NotNull String name, int age, int height, int width) {

   Intrinsics.checkNotNullParameter(name, "name");

}

可以看到确实重载了两个同名不同参的方法。但是,奇怪的是,重载方法里多了一些数字参数,8,12。

122.png

123.png

我们实际调用一下这个函数,再看一下反编译之后的代码

fun test() {

    overloadFun("Bril", 25)

    overloadFun("Bril", 25, 175)

    overloadFun("Bril", 25, 175, 130)

}

反编译之后

public final void test() {

   overloadFun$default(this, "Bril", 25, 0, 0, 12, (Object)null);

   overloadFun$default(this, "Bril", 25, 175, 0, 8, (Object)null);

   this.overloadFun("Bril", 25, 175, 130);

}

这里面出现了奇怪的数字参数8和12,为什么会出现8和12这些个数字呢?

原理

其实这里是一个非常巧的操作,以这个函数为例,有4个参数,也就是4个位置,每个位置有一个mask值,为2的n-1次方(n就是位置的顺序),所以这四个位置代表的mask值分别为:1,2,4,8。上面的8等于0+0+8+0,12等于0+0+4+8,看出来了规律了吗?如果当前位置没有参数调用,那么就将其mask值累加,最后得到一个结果。

// $FF: synthetic method

public static void overloadFun$default(ImageTemplateDelegateV2 var0, String var1, int var2, int var3, int var4, int var5, Object var6) {

   if ((var5 & 4) != 0) {

      var3 = 0;

   }



   if ((var5 & 8) != 0) {

      var4 = 0;

   }



   var0.overloadFun(var1, var2, var3, var4);

}

然后将该结果分别与对应的mask值进行与运算,就可以得知该位置有没有参数调用,如果没有,就对该参数赋予默认值,这就实现了参数默认值的效果。

注意

在自定义EditText的时候,有时候会发现拿不到焦点,其原因是

124.png

这里第三个参数值是R.attr.editTextStyle,而不是我们经常赋值的0,要注意!其他自定义控件有可能也遇到这种情况,可以根据这个线索进行排查。