当我们给构造函数指定了默认值,并且存在重载的构造函数,
比如如下场景
class Foo(val a: String, val b: Boolean = false) {
}
// 调用Foo("hello") 此时b是true
// 修改Foo类定义
class Foo(val a: String, val b: Boolean = false) {
constructor(a: String): this(a, false) {}
}
// 此时调用Foo("hello") 此时b是false
如上代码场景,kotlin是如何决定在重载的时候调用哪一个构造函数呢?
首先kotlin是如何处理含有默认值的函数的编译的?
kotlin会往原始函数后追加两个参数,一个是mask,一个是DefaultConstructorMarker,mask的作用用来告知哪一些默认参数是显示传递的,哪一些默认参数是使用默认值的,DefaultConstructorMarker是为了避免构造函数冲突,假设我有另外一个构造函数参数相同,末尾也是int,不加标记区分,无法区分这两个构造函数,实际调用过程中,这个构造函数始终为空。
举个例子,以上图中的Foo为例子
class Foo(val a: String, val b: Boolean = false) {
}
这个构造函数经过kotlin编译器处理后会变成
class Foo {
public Foo(@NotNull String a, boolean b) {
Intrinsics.checkNotNullParameter(a, "a");
super();
this.a = a;
this.b = b;
}
public Foo(String var1, boolean var2, int var3, DefaultConstructorMarker var4) {
if ((var3 & 2) != 0) {
var2 = false;
}
this(var1, var2);
}
}
会生成两个函数,一个函数是两个值都指定的,还有一个函数是会使用默认值的。
重载决议: 选择最具体最合适的函数
如何定义最具体:kotlin的标准是如果一个构造函数使用的默认值更少,那么这个构造函数更具体,
回到上文的例子,
- 对比调用点和对应的构造函数,如上例子,如果选择Foo(val a: String, val b: Boolean = false) ,那么有1个参数使用默认值,如果选择constructor(a: String),针对构造函数参数来说,这个构造函数不需要使用默认值。因此最终构造函数决议会使用这个构造函数。