Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )相关的知识,希望对你有一定的参考价值。
文章目录
一、init 初始化块
在 Kotlin 类中 , 可以定义 init 初始化块 , 在其中可以为 变量赋值 , 执行一些检查相关的代码 , 该 init 初始化块在 创建类实例对象 时执行 ;
代码示例 : 在下面的代码中的 init 初始化块 中 , 对 name 属性进行了修改 , 检查了 age 属性是否合法 ;
class Hello(
// 主构造函数, 直接在主构造函数中定义属性
var name: String,
var age: Int
)
init
// 将 name 属性首字母大写
name = name.capitalize()
// 检查 age 是否合法
// 如果不符合要求, 则抛出异常
require(age > 0)
println("年龄必须大于 0")
fun main()
var hello = Hello("tom", 18)
println(hello.name + " , " + hello.age)
var hello2 = Hello("jerry", -1)
执行结果 :
Tom , 18
年龄必须大于 0
Exception in thread "main" java.lang.IllegalArgumentException: kotlin.Unit
at Hello.<init>(Hello.kt:11)
at HelloKt.main(Hello.kt:21)
at HelloKt.main(Hello.kt)
二、初始化顺序
Kotlin 类 对象在实例化 时会执行一系列的 初始化操作 , 这些操作按照如下顺序执行 :
- 主构造函数 中属性赋值
- 类中的属性赋值
- init 初始化块 中的代码执行
- 次构造函数 中的代码执行
代码示例 : 通过下面的代码分析 Kotlin 实例对象 各种初始化操作的 初始化顺序 ;
class Hello(
// 主构造函数, 直接在主构造函数中定义属性
var name: String,
// 该值是临时变量, 为 age 属性赋值
_age: Int
)
// 类中的属性
var age = _age
var type = "老鼠"
var gender: String
init
println("init 初始化块开始执行")
gender = "男"
constructor(_age: Int): this("Tom", _age)
println("次构造函数开始执行")
type = "猫"
fun main()
var hello = Hello(18)
println(hello.name + " , " + hello.age)
执行结果 :
init 初始化块开始执行
次构造函数开始执行
Tom , 18
从上述执行结果上看 , 可以知道先执行 init 初始化块 , 然后执行 次构造函数 ;
查看 Kotlin 字节码 , 并将其反编译回 Java 代码 , 结果如下 :
// HelloKt.java
import kotlin.Metadata;
@Metadata(
mv = 1, 4, 2,
bv = 1, 0, 3,
k = 2,
d1 = "\\u0000\\b\\n\\u0000\\n\\u0002\\u0010\\u0002\\n\\u0000\\u001a\\u0006\\u0010\\u0000\\u001a\\u00020\\u0001¨\\u0006\\u0002",
d2 = "main", "", "KotlinDemo"
)
public final class HelloKt
public static final void main()
Hello hello = new Hello(18);
String var1 = hello.getName() + " , " + hello.getAge();
boolean var2 = false;
System.out.println(var1);
// $FF: synthetic method
public static void main(String[] var0)
main();
// Hello.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = 1, 4, 2,
bv = 1, 0, 3,
k = 1,
d1 = "\\u0000\\u001a\\n\\u0002\\u0018\\u0002\\n\\u0002\\u0010\\u0000\\n\\u0000\\n\\u0002\\u0010\\b\\n\\u0002\\b\\u0002\\n\\u0002\\u0010\\u000e\\n\\u0002\\b\\u0010\\u0018\\u00002\\u00020\\u0001B\\u000f\\b\\u0016\\u0012\\u0006\\u0010\\u0002\\u001a\\u00020\\u0003¢\\u0006\\u0002\\u0010\\u0004B\\u0015\\u0012\\u0006\\u0010\\u0005\\u001a\\u00020\\u0006\\u0012\\u0006\\u0010\\u0002\\u001a\\u00020\\u0003¢\\u0006\\u0002\\u0010\\u0007R\\u001a\\u0010\\b\\u001a\\u00020\\u0003X\\u0086\\u000e¢\\u0006\\u000e\\n\\u0000\\u001a\\u0004\\b\\t\\u0010\\n\\"\\u0004\\b\\u000b\\u0010\\u0004R\\u001a\\u0010\\f\\u001a\\u00020\\u0006X\\u0086\\u000e¢\\u0006\\u000e\\n\\u0000\\u001a\\u0004\\b\\r\\u0010\\u000e\\"\\u0004\\b\\u000f\\u0010\\u0010R\\u001a\\u0010\\u0005\\u001a\\u00020\\u0006X\\u0086\\u000e¢\\u0006\\u000e\\n\\u0000\\u001a\\u0004\\b\\u0011\\u0010\\u000e\\"\\u0004\\b\\u0012\\u0010\\u0010R\\u001a\\u0010\\u0013\\u001a\\u00020\\u0006X\\u0086\\u000e¢\\u0006\\u000e\\n\\u0000\\u001a\\u0004\\b\\u0014\\u0010\\u000e\\"\\u0004\\b\\u0015\\u0010\\u0010¨\\u0006\\u0016",
d2 = "LHello;", "", "_age", "", "(I)V", "name", "", "(Ljava/lang/String;I)V", "age", "getAge", "()I", "setAge", "gender", "getGender", "()Ljava/lang/String;", "setGender", "(Ljava/lang/String;)V", "getName", "setName", "type", "getType", "setType", "KotlinDemo"
)
public final class Hello
private int age;
@NotNull
private String type;
@NotNull
private String gender;
@NotNull
private String name;
public final int getAge()
return this.age;
public final void setAge(int var1)
this.age = var1;
@NotNull
public final String getType()
return this.type;
public final void setType(@NotNull String var1)
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.type = var1;
@NotNull
public final String getGender()
return this.gender;
public final void setGender(@NotNull String var1)
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.gender = var1;
@NotNull
public final String getName()
return this.name;
public final void setName(@NotNull String var1)
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
public Hello(@NotNull String name, int _age)
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = _age;
this.type = "老鼠";
String var3 = "init 初始化块开始执行";
boolean var4 = false;
System.out.println(var3);
this.gender = "男";
public Hello(int _age)
this("Tom", _age);
String var2 = "次构造函数开始执行";
boolean var3 = false;
System.out.println(var2);
this.type = "猫";
重点分析 构造函数 :
public Hello(@NotNull String name, int _age)
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = _age;
this.type = "老鼠";
String var3 = "init 初始化块开始执行";
boolean var4 = false;
System.out.println(var3);
this.gender = "男";
在上述 构造函数中 :
首先 , 为 name
属性赋值 , 这是在 主构造函数 中完成的操作 ;
然后 , 为 age
和 type
属性赋值 , 这是在 类 中的 age 属性进行的赋值 , 使用的是 主构造函数 中的临时变量 ;
最后 , 为 gender
赋值 , 这是在 init 初始化块 中进行的赋值 ;
然后分析 次构造函数 , 在 如下的 次构造函数的代码中 , 先执行了 主构造函数 , 然后才为 type
属性赋值 , 这是在次构造函数中执行的 , 这是最后执行的代码 ;
public Hello(int _age)
this("Tom", _age);
String var2 = "次构造函数开始执行";
boolean var3 = false;
System.out.println(var2);
this.type = "猫";
因此得到了上述初始化操作的执行顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码
以上是关于Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 主构造函数 次构造函数 默认参数 init代码块 初始化顺序
错误记录Kotlin 代码运行时报错 ( 在 init 初始化块中调用还未初始化的成员属性 )