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

相关推荐
日光明媚35 分钟前
一步生成视频!One-Forcing:DMD + 零成本 GAN,训练 200 步超越多步 SOTA
android·开发语言·kotlin
帅次1 小时前
Android 17 开发者实战:核心更新与应用场景落地指南
android·java·ios·android studio·iphone·android jetpack·webview
大鹏说大话2 小时前
SQL 排序与分组实战:解决“分组后取最新数据“
android·java·数据库
plainGeekDev2 小时前
Android运行时面试题:ART和JVM的区别都搞不清,别写精通了
jvm·面试·kotlin
搜狐技术产品小编20234 小时前
破局与重构:纯端侧 Android 自动化引擎的尝试与未来推演
android·运维·重构·自动化
码云骑士5 小时前
Android SystemServer启动过程
android·systemserver
weiggle6 小时前
第三篇:可组合函数(Composable)——Compose 的基石
android·前端
独隅7 小时前
Android Studio 接入多种不同 AI 大模型进行开发的全面详细指南(Android Studio+AI)
android·人工智能·android studio
夜微凉47 小时前
三、MySQL
android·数据库·mysql
我命由我123457 小时前
Android 开发问题:项目同时引入了两个包含相同类文件的库(AndroidX 库、旧版本支持库),导致了重复类错误
android·java·java-ee·android studio·android-studio·androidx·android runtime