一 主构造函数 (Primary Constructor)
- 定义方式:
kotlin
class Person(val name: String, var age: Int) // 主构造函数
- 特点:
- 直接在类头部声明
- 每个类最多只能有一个主构造函数
- 可以声明属性和初始化属性
- 使用
init
块进行初始化代码 - 不能包含任何代码,初始化代码需要放在
init
块中
次构造函数 (Secondary Constructor)
- 定义方式:
kotlin
class Person {
constructor(name: String) { // 次构造函数
// 初始化代码
}
}
- 特点:
- 在类体内声明
- 可以有多个次构造函数
- 必须直接或间接调用主构造函数
- 可以直接包含初始化代码
完整示例
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
}
}
区别总结
-
数量限制:
- 主构造函数:最多一个
- 次构造函数:可以有多个
-
声明位置:
- 主构造函数:类头部
- 次构造函数:类体内
-
初始化代码:
- 主构造函数:使用
init
块 - 次构造函数:直接在构造函数体内
- 主构造函数:使用
-
调用关系:
- 主构造函数:被次构造函数调用
- 次构造函数:必须调用主构造函数或其他次构造函数
-
属性声明:
- 主构造函数:可以直接声明属性
- 次构造函数:不能声明属性
二 主构造函数的声明方式和参数区别解释
主构造函数声明
- 基本声明方式:
kotlin
// 方式1:直接在类名后声明
class Person(name: String, age: Int)
// 方式2:使用 constructor 关键字
class Person constructor(name: String, age: Int)
参数区别
- 不加 val/var:
kotlin
class Person(name: String) {
// name 只能在 init 块或构造函数内使用
init {
println(name) // 可以访问
}
fun printName() {
// println(name) // 编译错误:无法访问 name
}
}
- 加 val/var:
kotlin
class Person(val name: String, var age: Int) {
// name 和 age 变成了类的属性
init {
println(name) // 可以访问
}
fun printName() {
println(name) // 可以访问
age += 1 // 可以修改 var 声明的属性
}
}
区别总结:
-
不加 val/var:
- 参数仅在初始化过程中可用
- 不会成为类的属性
- 只能在 init 块和构造函数中访问
- 不占用额外内存
-
加 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 的情况
当主构造函数:
- 没有注解(@符号开头的修饰)
- 没有可见性修饰符(public、private、protected、internal)
kotlin
// 可以省略 constructor
class Person(val name: String, var age: Int)
// 等价于
class Person constructor(val name: String, var age: Int)
不能省略 constructor 的情况
- 有可见性修饰符时:
kotlin
// 不能省略 constructor
class Person private constructor(val name: String)
- 有注解时:
kotlin
// 不能省略 constructor
class Person @Inject constructor(val name: String)
- 同时有注解和可见性修饰符时:
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
,但没有指定修饰符 (比如private
、internal
),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
来控制访问权限
参考: