Kotlin 中初始化块、初始化的顺序、lateinit延迟初始化详解

简介: Kotlin 中初始化块、初始化的顺序、lateinit延迟初始化详解

1、初始化块:初始化块可以设置变量或值,以及执行有效性检查,如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。

案例代码如下:

class Player3(
    _name: String, var age: Int = 20, var isNormal: Boolean
) {
    var name = _name
        get() = field.capitalize()
        set(value) {
            field = value.trim()
        }
    //次构造函数
    //我们可以定义多个次构造函数来配置不同的参数组合
    constructor(name: String) : this(name, age = 100, isNormal = false)
    constructor(name: String, age: Int) : this(name, age = 10, isNormal = false) {
        println("次构造函数")
        this.name = name.toUpperCase()
    }
    init {
        println("测试init")
        require(age > 0) {
            "age muse be positive"
        }
        require(name.isNotBlank()) {
            "player must have a name"
        }
    }
}
fun main() {
    val player = Player3(isNormal = false, _name = "Jack")
    println("${player.name}, ${player.age}, ${player.isNormal}")
    val p = Player3("Android", 10)
    println("${p.name},${p.age},${p.isNormal}")
}

输出结果如下:

测试init
Jack, 20, false
测试init
次构造函数
ANDROID,10,false

2.初始化执行的顺序

  1. 主构造函数里声明的属性
  2. 类级别的属性赋值
  3. init初始块里的属性赋值和函数调用
  4. 次构造函数里的属性赋值和函数调用

案例代码如下:

class Students(
    _name: String, val age: Int
) {
    var name = _name
    var score = 10
    private val hobby = "music"
    val subject: String
  //初始化块
    init {
        println("initializing Students...")
        subject = "math"
    }
    constructor(_name: String) : this(_name, 10) {
        score = 20
    }
}
fun main() {
    Students("Jack")
}

可以通过反编译看java代码,就清楚了,反编译代码如下

public final class StudentsKt {
   public static final void main() {
      new Students("Jack");
   }
   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
// Students.java
package kotlin04;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
   mv = {1, 6, 0},
   k = 1,
   d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010\b\n\u0002\b\u000f\u0018\u00002\u00020\u0001B\u000f\b\u0016\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0005\u001a\u00020\u0006¢\u0006\u0002\u0010\u0007R\u0011\u0010\u0005\u001a\u00020\u0006¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\tR\u000e\u0010\n\u001a\u00020\u0003X\u0082D¢\u0006\u0002\n\u0000R\u001a\u0010\u000b\u001a\u00020\u0003X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\f\u0010\r\"\u0004\b\u000e\u0010\u0004R\u001a\u0010\u000f\u001a\u00020\u0006X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0010\u0010\t\"\u0004\b\u0011\u0010\u0012R\u0011\u0010\u0013\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u0014\u0010\r¨\u0006\u0015"},
   d2 = {"Lkotlin04/Students;", "", "_name", "", "(Ljava/lang/String;)V", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "hobby", "name", "getName", "()Ljava/lang/String;", "setName", "score", "getScore", "setScore", "(I)V", "subject", "getSubject", "kotlinStudy"}
)
public final class Students {
   @NotNull
   private String name;
   private int score;
   private final String hobby;
   @NotNull
   private final String subject;
   private final int age;
   @NotNull
   public final String getName() {
      return this.name;
   }
   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }
   public final int getScore() {
      return this.score;
   }
   public final void setScore(int var1) {
      this.score = var1;
   }
   @NotNull
   public final String getSubject() {
      return this.subject;
   }
   public final int getAge() {
      return this.age;
   }
   public Students(@NotNull String _name, int age) {
      Intrinsics.checkNotNullParameter(_name, "_name");
      super();
      this.age = age;
      this.name = _name;
      this.score = 10;
      this.hobby = "music";
      String var3 = "initializing Students...";
      System.out.println(var3);
      this.subject = "math";
   }
   public Students(@NotNull String _name) {
      Intrinsics.checkNotNullParameter(_name, "_name");
      this(_name, 10);
      this.score = 20;
   }
}

3、延迟初始化lateinit

class Player4 {
    lateinit var equipment: String
    fun ready() {
        equipment = "sharp knife"
    }
    fun battle() {
        if (::equipment.isInitialized) {//该属性初始化,执行该代码
            println(equipment)
        }
    }
}
fun main() {
    val p = Player4()
    p.ready()
    p.battle()
}

输出结果

sharp knife


目录
相关文章
|
4月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
151 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
Cloud Native Go Kotlin
Kotlin 环境下解决属性初始化问题
Kotlin 环境下解决属性初始化问题
61 0
|
Java 开发者 Kotlin
Kotlin中的 lateinit 和 by lazy
Kotlin中的 lateinit 和 by lazy
191 0
|
Java Kotlin
能说一说 Kotlin 中 lateinit 和 lazy 的区别吗?
能说一说 Kotlin 中 lateinit 和 lazy 的区别吗?
|
Java 编译器 开发者
【Kotlin】变量简介 ( 可空类型 | lateinit | 初始化判定 | 非空类型 | !! 与 ? 修饰符 | ?= ?. ?: 运算符 | 抽象属性变量)(一)
【Kotlin】变量简介 ( 可空类型 | lateinit | 初始化判定 | 非空类型 | !! 与 ? 修饰符 | ?= ?. ?: 运算符 | 抽象属性变量)(一)
385 0
【Kotlin】变量简介 ( 可空类型 | lateinit | 初始化判定 | 非空类型 | !! 与 ? 修饰符 | ?= ?. ?: 运算符 | 抽象属性变量)(一)
|
存储 Kotlin
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
221 0
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
|
Java Kotlin
【Kotlin】变量简介 ( 可空类型 | lateinit | 初始化判定 | 非空类型 | !! 与 ? 修饰符 | ?= ?. ?: 运算符 | 抽象属性变量)(二)
【Kotlin】变量简介 ( 可空类型 | lateinit | 初始化判定 | 非空类型 | !! 与 ? 修饰符 | ?= ?. ?: 运算符 | 抽象属性变量)(二)
225 0
|
1月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
20 1
|
2月前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
76 1
|
3月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
61 4