kotlin的代码初始化顺序其实我们DeCompile一下就可以看的明明白白了,先来看两个类,子类Sheep
和父类Animal
,找个地方初始化Sheep
即可:
open class Animal(name: String) {
open var name: String = "I'm a Animal"
set(value) {
field = value
}
get() = field
init {
this.name = "My Name is Animal from init block!"
init()
}
open fun init() {
name = "My Name is Animal from init function!"
}
}
class Sheep : Animal("Sheep") {
override var name = "I'm a Sheep"
set(value) {
field = value
}
get() = field
init {
this.name = name
}
override fun init() {
super.init()
this.name = "My Name is Sheep from init function!"
}
}
最后上一个Decompile kotlin的文件看一下应该对执行顺序有所了解了。
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0006\n\u0002\u0010\u0002\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\b\u0010\n\u001a\u00020\u000bH\u0016R&\u0010\u0005\u001a\u00020\u00042\u0006\u0010\u0003\u001a\u00020\u00048V@VX\u0096\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0006\u0010\u0007\"\u0004\b\b\u0010\t¨\u0006\f"},
d2 = {"Lcom/example/lw/grouphelper/Sheep;", "Lcom/example/lw/grouphelper/Animal;", "()V", "value", "", "name", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "init", "", "app_debug"}
)
public final class Sheep extends Animal {
@NotNull
private String name = "I'm a Sheep";
@NotNull
public String getName() {
return this.name;
}
public void setName(@NotNull String value) {
Intrinsics.checkParameterIsNotNull(value, "value");
this.name = value;
}
public void init() {
super.init();
this.setName("My Name is Sheep from init function!");
Log.e("Sheep", this.getName());
}
public Sheep() {
super("Sheep");
this.setName(this.getName());
Log.e("Sheep", this.getName());
}
}
- 1.首先是父类的变量
name
被赋值,注意:赋值的状态是Animal.name
,而不是name
或者this.name
,并且在Debug
状态下,断点不会停在赋值的位置,我也不知道原因在哪里。 - 2.接着是父类
Animal
的init{}
初始化代码块。 - 3.当
name
被赋值的时候,因为变量的继承关系,调用的是子类里name
的set
方法。 - 4.
Sheep
的init()
函数。 - 5.
Animal
的init()
函数。 - 6.
Sheep
中name
的set
函数。 - 7.最后是
Sheep
的init{}
总结
屏幕快照 2019-07-09 下午9.48.05.png
1.父类变量的赋值操作是最先被调用的,像Animal.name
,在initializer block
之前已经有值了:
2.子类的init{}
总是最后被调用。
3.因为变量的继承关系,子类中重写的变量的赋值总是调用子类相应变量的set
方法,而不是父类的。
网友评论