刚刚开始接触Kotlin,尤其是涉及Java-Kotlin混合开发的人,对于注解JvmOverloads
,一定不陌生。今天的主题,就是这个货。
JvmOverloads
首先,来看看注解JvmOverloads
的注释
Instructs the Kotlin compiler to generate overloads for this function that substitute default parameter values. If a method has N parameters and M of which have default values, M overloads are generated: the first one takes N-1 parameters (all but the last one that takes a default value), the second takes N-2 parameters, and so on.
要点:
- 注解的作用:告知编译器产生重载方法,以消除默认值参数方法的存在 —— 即以多个重载方法实现“默认参数值”
- 如果一个方法有N个参数,其中M个有默认值。那么会产生M个重载方法
-
上述M个方法:
- 第1个方法:有N-1个参数,最后1个参数使用默认值
- 第2个方法:有N-2个参数,最后2个参数使用默认值
- …
- 第M个方法:有N-M个参数,最后M个参数使用默认值
也就是说,带默认值参数的kotlin方法转为java代码后,则变成了多个重载方法。
那么,这个转换过程是怎么样的呢?是什么原理?
原理
一段测试代码如下:
1 |
|
测试类Test
定义了一个方法testParam
,该方法共4个参数,后3个参数各带了一个默认值。
来看看上述代码生成的java代码:
1 |
|
总共生成了3个重载方法,与带默认值的参数的数量一致。这些重载方法是怎么做到“默认参数值功能”的呢?
先来看看静态合成方法testParam$default
,它有7个参数:
var0
:对象this引用var1~var4
:分别对应四个参数var5
:一个标志值(什么用处呢?)var6
:未使用
而三个重载方法都直接调用了上述合成方法,传入了不同参数。
首先来看看全部使用默认值的方法C。原始声明里,三个默认值依次是:4, true, “hello”,而这里传入合成方法的是:0, false, null。var5
传入了14,var6
传入null。
很费解,这里14是什么意思?为什么全部使用默认值的方法,反而一个默认值都没传进去?再回头来看看合成方法就明白了。
1 |
|
看完上面的代码和注释,是不是原理呼之欲出?
参数序列,用一个整型由低位到高位依次标志,0代表没有默认值,1代表有默认值;不同的重载方法使用不同的标志位,来确定哪些参数将使用默认值。
方法C
传入的14,即0b1110
,var2~var4的标志分别为: 0b10
, 0b100
, 0b1000
,所以14即代表,这三个参数都使用默认值。
再来分析方法B
来验证上述结论:var3和var4使用默认值,传入无效参数false和null,标志位是12(即0b1100),自然,调用合成方法,只有高位两位满足,即var3和var4使用默认值。结论正确。
小结
默认参数方法到重载方法,巧妙地使用了“按位取值”,把默认参数值与重载方法一一对应起来了。