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

相关推荐
wzj_what_why_how3 小时前
Android网络层架构:统一错误处理的问题分析到解决方案与设计实现
android·架构
千里马学框架3 小时前
User手机上如何抓取界面的布局uiautomatorviewer
android·智能手机·aosp·uiautomator·布局抓取·user版本
阿巴~阿巴~3 小时前
操作系统核心技术剖析:从Android驱动模型到鸿蒙微内核的国产化实践
android·华为·harmonyos
hsx6664 小时前
使用 MaterialShapeDrawable 自定义各种形状的 View
android
用户2018792831675 小时前
滑动城堡的奇妙管家 ——ViewPager故事
android
用户2018792831675 小时前
📜 童话:魔法卷轴与 ScrollView 的奥秘
android
hsx6665 小时前
Kotlin 协程中的 Dispatchers
kotlin
??? Meggie6 小时前
【SQL】使用UPDATE修改表字段的时候,遇到1054 或者1064的问题怎么办?
android·数据库·sql
用户2018792831676 小时前
代码共享法宝之maven-publish
android
yjm6 小时前
从一例 Lottie OOM 线上事故读源码
android·app