Kotlin 类与构造函数


一、类的声明与主构造函数

// 最简形式:无参主构造函数
class User

// 带参数的主构造函数(直接在类名后声明)
class User(val name: String, var age: Int)

// 完整写法(constructor关键字可省略)
class User public constructor(name: String) {
    val userName: String = name
}

关键点:

  • val 参数 → 生成只读属性 + getter
  • var 参数 → 生成可读写属性 + getter/setter
  • 普通参数 → 仅作为构造参数使用,不生成属性

二、init 初始化块

init 块在主构造函数执行时立即运行,按声明顺序执行,常用于参数校验和初始化逻辑。

class Student(val name: String, val age: Int) {
    
    val studentId: String
    
    init {
        // 参数校验
        require(name.isNotBlank()) { "姓名不能为空" }
        require(age in 6..30) { "年龄必须在6-30之间" }
        
        // 复杂初始化
        studentId = "S${System.currentTimeMillis()}"
        println("学生 $name 初始化完成")
    }
    
    // 可以有多个init块,按顺序执行
    init {
        println("第二个init块执行")
    }
}

对比Java:

// Java写法
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        // 校验和初始化逻辑写在这里
    }
}

Kotlin 的 init 块将初始化逻辑与构造参数分离,更清晰。


三、次构造函数

使用 constructor 关键字定义,必须直接或间接委托给主构造函数。

class Person(val name: String, val age: Int) {
    
    // 委托给主构造函数
    constructor(name: String) : this(name, 0) {
        println("次构造函数:只有姓名")
    }
    
    // 委托给另一个次构造函数
    constructor() : this("Unknown", 0) {
        println("次构造函数:无参数")
    }
}

// 使用
val p1 = Person("Alice", 25)      // 主构造
val p2 = Person("Bob")            // 次构造1
val p3 = Person()                 // 次构造2

执行顺序:主构造 → init块 → 次构造函数体

class Demo(name: String) {
    init { println("1. init块执行") }
    constructor(name: String, age: Int) : this(name) {
        println("2. 次构造函数体执行")
    }
}
// 调用 Demo("A", 18) 输出顺序:1 → 2

四、属性声明与 getter/setter

主构造函数中的属性可以自定义访问器:

class Rectangle(val width: Int, val height: Int) {
    // 自定义getter(每次计算)
    val area: Int
        get() = width * height
    
    // 带field关键字的setter(支持幕后字段)
    var perimeter: Int = 0
        set(value) {
            field = value  // field是幕后字段,避免递归
            println("周长已更新为 $value")
        }
}

幕后字段 field:在自定义getter/setter中代表实际存储值的字段,仅在需要时使用。


五、属性初始化时机(容易踩坑)

class MyClass(val name: String) {
    val upperName = name.uppercase()  // ✅ 直接用构造参数
    
    val greeting: String
        get() = "Hello $name"  // ✅ 每次调用时计算
    
    // ❌ 错误:lateinit属性不能与getter一起用
    // lateinit var message: String
    //     get() = field ?: "default"
    
    // ✅ lateinit用于延迟初始化(var,非空类型)
    lateinit var dynamicData: String
    
    // ✅ by lazy用于懒加载(val,只读)
    val heavyObject: HeavyClass by lazy { 
        HeavyClass()  // 首次访问时才初始化
    }
}

六、可见性与构造函数的组合

// 主构造函数私有(工厂模式)
class Singleton private constructor(val id: Int) {
    companion object {
        fun create(id: Int) = Singleton(id)
    }
}

// 构造参数可见性控制
class User internal constructor(val name: String)  // 模块内可见

// 属性可见性独立控制
class Product(val name: String) {
    var price: Double = 0.0
        private set  // setter私有,外部只读
}

七、完整实战示例

// 用户实体类(数据类+主构造)
data class User(
    val id: Long,
    val username: String,
    private var _email: String
) {
    // 带校验的setter
    var email: String
        get() = _email
        set(value) {
            require(value.contains("@")) { "邮箱格式不正确" }
            _email = value
        }
    
    // 次构造:便捷创建
    constructor(username: String) : this(0, username, "$username@default.com")
    
    init {
        require(username.length >= 3) { "用户名至少3个字符" }
    }
    
    // 派生属性
    val isPremium: Boolean
        get() = id > 1000
}

// 使用
fun main() {
    val user = User(1001, "alice", "alice@mail.com")
    user.email = "new@mail.com"  // 调用setter校验
    // user._email  // ❌ 私有不可访问
    
    val guest = User("guest")  // 次构造
    println(guest.email)  // guest@default.com
}

关键对比总结

特性 Kotlin Java
构造参数声明 直接在类名后 在类体内声明
初始化逻辑 init块 构造方法内
属性+构造合一 ✅ val/var参数 ❌ 需手动赋值
多个构造 主构造+次构造(必须委托) 多个构造方法(可互相调用)
默认构造 自动生成无参构造 没写构造才有默认

常见陷阱提醒 🚨

  1. 次构造函数不能声明属性:constructor(val name: String) ❌ 这是错误的,参数不能加val/var
  2. init块在次构造函数体之前执行:别把依赖次构造参数的逻辑写在init里
  3. data class不能有无参主构造:data class主构造至少要有一个参数
  4. lateinit var不能是基本类型:Int、Boolean等不能用lateinit(可用by lazy替代)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容