kotlin类的初始化③(init初始化块|初始化顺序:主构造函数属性赋值->类属性赋值->init初始化块代码->次构造函数代码)(代码片段)

韩曙亮 韩曙亮     2023-01-19     572

关键词:

文章目录





一、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 初始化块代码 -> 次构造函数代码

错误记录kotlin代码运行时报错(在init初始化块中调用还未初始化的成员属性)(代码片段)

...问题分析三、解决方案该问题的本质就是,成员属性在init初始化代码块中进行初始化,但是在初始化之前调用了该成员属性,编译时没有报错信息,但是运行时会报异常;一、报错信息执行如下代码:classHellovarname:StringfunnameFirstLetter()... 查看详情

错误记录kotlin代码运行时报错(在init初始化块中调用还未初始化的成员属性)(代码片段)

...问题分析三、解决方案该问题的本质就是,成员属性在init初始化代码块中进行初始化,但是在初始化之前调用了该成员属性,编译时没有报错信息,但是运行时会报异常;一、报错信息执行如下代码:classHellovarname:StringfunnameFirstLetter()... 查看详情

错误记录kotlin代码编译时报错(variable‘name‘mustbeinitialized|初始化块定义在所有属性之后)(代码片段)

文章目录一、报错信息二、问题分析三、解决方案(初始化块定义在所有属性之后)一、报错信息在Kotlin中,init初始化块要定义在所有成员属性之后;如果在init初始化块中,使用到了成员属性,有可能出现编译时报错信息;报错代码示例... 查看详情

错误记录kotlin代码编译时报错(variable‘name‘mustbeinitialized|初始化块定义在所有属性之后)(代码片段)

文章目录一、报错信息二、问题分析三、解决方案(初始化块定义在所有属性之后)一、报错信息在Kotlin中,init初始化块要定义在所有成员属性之后;如果在init初始化块中,使用到了成员属性,有可能出现编译时报错信息;报错代码示例... 查看详情

kotlin主构造函数次构造函数默认参数init代码块初始化顺序(代码片段)

packagesetimportjava.util.*importkotlin.math.absoluteValue//临时变量只是用一次推荐使用下划线开头classPlayer(_name:String,_age:Int,_isNormal:Boolean//构造参数)//属性varname=_nameget()=field.replaceFirstCharif(it.isLowerCase())it.titlecase(Locale.getDefault())elseit.toS... 查看详情

kotlin学习与实践构造方法

...了一点修改:*区分了主构造方法(通常是主要而简洁的初始化类的方法,并且声明在类外部声明)和从构造方法(在类的内部声明)*同样也允许在初始化语句块中添加额外的初始化逻辑。/***这里被括号围起来的语句块就叫做“... 查看详情

类的初始化

类的初始化时类加载的最后一步,此时才开始执行Java代码(字节码)。初始化阶段是开始执行clinit<>()方法的过程。clinit<>():由编译器收集类中的类变量赋值操作和static代码块中的语句合并产生的,收集顺序与源文件中... 查看详情

SpringBoot 中的 Kotlin - `init`-blocks 的初始化顺序

】SpringBoot中的Kotlin-`init`-blocks的初始化顺序【英文标题】:KotlininSpringBoot-initializationorderfor`init`-blocks【发布时间】:2021-01-2305:03:13【问题描述】:以下情况是在Kotlin和SpringBoot上下文中。我想知道Kotlin的init块的初始化是在所有依... 查看详情

类的初始化__init__使用(代码片段)

初始化方法:作用:对新创建的对象添加属性语法:class类名(继承列表):def__init__(self[,形参列表]):语句块[]代表中的内容可省略说明:1.实始化方法名必须为‘__init__‘不可改变2.初始化方法会在构造函数创建实例后自动调用.且将实例自... 查看详情

kotlin类与继承

...型参数)后主构造函数不能包含任何代码块,可用init块初始化代码,并且可访问主构造函数的 查看详情

类加载过程(clinit()),对象实例化过程(init())

...clinit方法。3、clinit方法中的执行顺序为:父类静态变量初始化,父类静态代码块,子类静态变量初始化,子类静态代码块。4、clinit()方法只执行一次。对象实例化过程:1、对象实例化过程就是执行Java程序编译之后在字节码文件... 查看详情

执行顺序

类初始化过程  一个类要创建实例需要先加载并初始化该类    main方法所在的类需要先加载和初始化   一个子类要初始化需要先初始化父类  一个类初始化就是执行<clinit>()方法       <clinit>()... 查看详情

kotlin中初始化块初始化的顺序lateinit延迟初始化详解(代码片段)

...有意思,忍不住分享一下给大家。👉点击跳转教程1、初始化块:初始化块可以设置变量或值,以及执行有效性检查,如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。案例代码如下&#... 查看详情

kotlin中初始化块初始化的顺序lateinit延迟初始化详解(代码片段)

...有意思,忍不住分享一下给大家。👉点击跳转教程1、初始化块:初始化块可以设置变量或值,以及执行有效性检查,如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。案例代码如下&#... 查看详情

kotlininit小记(代码片段)

Kotlin提供了初始化式块(也称为init块),作为对象实例初始化期间所需的初始设置代码的位置。初始化式块带有前缀init关键字,后跟花括号。此代码块将于首次创建和初始化对象实例时运行。如设置变量或值ÿ... 查看详情

杂谈6

1.初始化块分静态和动态块  静态块只能初始化静态量,动态块可以初始化静态和动态量,静态初始化块先于动态初始化块2.父类的默认构造器>子类的默认构造器,子类的默认构造器>父类的非默认构造器3.父类的静态... 查看详情

在活动的初始化块中使用“this”作为上下文?

】在活动的初始化块中使用“this”作为上下文?【英文标题】:Using\'this\'asContextintheinitblockofactivity?【发布时间】:2020-05-1121:18:27【问题描述】:我正在使用kotlin开发一个android应用程序。我有一个DereDatabaseHelper类,它有一个init... 查看详情

类与对象归档

1,总结Java字段初始化的规律。 Java初始化的地方有两个:初始化块和构造函数,其中初始化又分为实例初始化块和静态初始化块,实例初始化块没有关键字修饰,而静态初始化块由static修饰。 执行类成员定义时指定的默... 查看详情