【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 属性赋值 , 这是在 主构造函数 中完成的操作 ;

然后 , 为 agetype 属性赋值 , 这是在 类 中的 age 属性进行的赋值 , 使用的是 主构造函数 中的临时变量 ;

最后 , 为 gender 赋值 , 这是在 init 初始化块 中进行的赋值 ;


然后分析 次构造函数 , 在 如下的 次构造函数的代码中 , 先执行了 主构造函数 , 然后才为 type 属性赋值 , 这是在次构造函数中执行的 , 这是最后执行的代码 ;

   public Hello(int _age) {
    
    
      this("Tom", _age);
      String var2 = "次构造函数开始执行";
      boolean var3 = false;
      System.out.println(var2);
      this.type = "猫";
   }

因此得到了上述初始化操作的执行顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/128721896
今日推荐