Kotlin 中主构造函数和次构造函数的区别

一 主构造函数 (Primary Constructor)

  1. 定义方式
kotlin 复制代码
class Person(val name: String, var age: Int) // 主构造函数
  1. 特点
  • 直接在类头部声明
  • 每个类最多只能有一个主构造函数
  • 可以声明属性和初始化属性
  • 使用 init 块进行初始化代码
  • 不能包含任何代码,初始化代码需要放在 init 块中

次构造函数 (Secondary Constructor)

  1. 定义方式
kotlin 复制代码
class Person {
    constructor(name: String) { // 次构造函数
        // 初始化代码
    }
}
  1. 特点
  • 在类体内声明
  • 可以有多个次构造函数
  • 必须直接或间接调用主构造函数
  • 可以直接包含初始化代码

完整示例

kotlin 复制代码
class Person(val name: String) { // 主构造函数
    var age: Int = 0
    var address: String = ""
    
    init {
        println("初始化块执行") // 主构造函数的初始化代码
    }
    
    constructor(name: String, age: Int) : this(name) { // 次构造函数1
        this.age = age
    }
    
    constructor(name: String, age: Int, address: String) : this(name, age) { // 次构造函数2
        this.address = address
    }
}

区别总结

  1. 数量限制

    • 主构造函数:最多一个
    • 次构造函数:可以有多个
  2. 声明位置

    • 主构造函数:类头部
    • 次构造函数:类体内
  3. 初始化代码

    • 主构造函数:使用 init
    • 次构造函数:直接在构造函数体内
  4. 调用关系

    • 主构造函数:被次构造函数调用
    • 次构造函数:必须调用主构造函数或其他次构造函数
  5. 属性声明

    • 主构造函数:可以直接声明属性
    • 次构造函数:不能声明属性

二 主构造函数的声明方式和参数区别解释

主构造函数声明

  1. 基本声明方式
kotlin 复制代码
// 方式1:直接在类名后声明
class Person(name: String, age: Int)

// 方式2:使用 constructor 关键字
class Person constructor(name: String, age: Int)

参数区别

  1. 不加 val/var
kotlin 复制代码
class Person(name: String) {
    // name 只能在 init 块或构造函数内使用
    init {
        println(name) // 可以访问
    }

    fun printName() {
        // println(name) // 编译错误:无法访问 name
    }
}
  1. 加 val/var
kotlin 复制代码
class Person(val name: String, var age: Int) {
    // name 和 age 变成了类的属性
    init {
        println(name) // 可以访问
    }

    fun printName() {
        println(name) // 可以访问
        age += 1 // 可以修改 var 声明的属性
    }
}

区别总结:

  1. 不加 val/var

    • 参数仅在初始化过程中可用
    • 不会成为类的属性
    • 只能在 init 块和构造函数中访问
    • 不占用额外内存
  2. 加 val/var

    • 参数自动成为类的属性
    • 可以在类的任何地方访问
    • val:只读属性(不可修改)
    • var:可读写属性(可以修改)
    • 会占用实例内存空间

实际示例:

kotlin 复制代码
class xxViewModel(
    private val xxModel: xxwModel, // 成为私有只读属性
    private val xxModel: xxModel          // 成为私有只读属性
) : ViewModel() {
    // 可以在类中任何地方访问 xxModel 和 xxodel
    init {
        // 可以使用这些属性
    }

    fun someMethod() {
        // 可以使用这些属性
        xxModel.updatexxLevel(xxMode.SPEED_1.value)
    }
}

让我通过例子说明 constructor 关键字的使用规则:

可以省略 constructor 的情况

当主构造函数:

  1. 没有注解(@符号开头的修饰)
  2. 没有可见性修饰符(public、private、protected、internal)
kotlin 复制代码
// 可以省略 constructor
class Person(val name: String, var age: Int)

// 等价于
class Person constructor(val name: String, var age: Int)

不能省略 constructor 的情况

  1. 有可见性修饰符时
kotlin 复制代码
// 不能省略 constructor
class Person private constructor(val name: String)
  1. 有注解时
kotlin 复制代码
// 不能省略 constructor
class Person @Inject constructor(val name: String)
  1. 同时有注解和可见性修饰符时
kotlin 复制代码
// 不能省略 constructor
class Person @Inject private constructor(val name: String)

总结:constructor 关键字的使用与否取决于构造函数是否需要修饰符或注解。没有这些额外修饰时可以省略,使代码更简洁。

四 在 Kotlin 中,如果没有显式指定可见性修饰符,constructor 默认会有一个修饰符吗?

是的,有的,默认修饰符是 public


📘 解释:

在 Kotlin 中,类的主构造函数可以这样声明:

kotlin 复制代码
class Person constructor(val name: String)

你也可以省略 constructor 关键字(如果没有注解或修饰符):

kotlin 复制代码
class Person(val name: String)
👉 关于可见性修饰符:
  • 如果你写了 constructor,但没有指定修饰符 (比如 privateinternal),Kotlin 默认使用 public 修饰符,这意味着构造函数是公开的。
  • 所以以下两种写法的可见性是一样的,都是 public
kotlin 复制代码
class Person constructor(val name: String) // public constructor

class Person(val name: String) // 等价写法,隐式 public

🧪 示例:

kotlin 复制代码
class Person constructor(val name: String)

fun main() {
    val p = Person("Alice") // ✅ 这是允许的,因为构造函数是 public
}

如果你显式指定 private

kotlin 复制代码
class Person private constructor(val name: String)

fun main() {
    val p = Person("Alice") // ❌ 错误:构造函数是 private
}

✅ 总结:

  • 默认可见性修饰符是 public
  • 如果你没有写修饰符,那它就是 public
  • 你可以使用 private / internal 等修饰 constructor 来控制访问权限

参考:

https://book.kotlincn.net/text/classes.html

相关推荐
xiangpanf9 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx12 小时前
安卓线程相关
android
消失的旧时光-194312 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon13 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon13 小时前
VSYNC 信号完整流程2
android
dalancon13 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户693717500138414 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android15 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才15 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶16 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle