ZetCode

Kotlin 伴生对象

最后修改于 2025 年 4 月 19 日

Kotlin 的伴生对象提供了一种定义类级别属性和方法的方式,类似于 Java 的静态成员。companion 关键字声明属于类而不是实例的这些成员。本教程通过实际例子深入探讨了伴生对象。

基本定义

伴生对象使用 companion 关键字在类中声明。它可以包含可以在不创建类实例的情况下调用的属性和方法。伴生对象在加载包含类时被初始化。

基本伴生对象

最简单的伴生对象形式提供了类级别的功能。成员可以直接使用类名访问,类似于 Java 中的静态成员。

BasicCompanion.kt
package com.zetcode

class MyClass {
    companion object {
        fun create(): MyClass = MyClass()
        val PI = 3.1415
    }
}

fun main() {

    val instance = MyClass.create()
    println(MyClass.PI) // Output: 3.1415
}

在这里,我们定义了一个伴生对象,其中包含一个工厂方法 create 和一个常量 PI。两者都通过类名访问,无需创建实例。这演示了基本伴生对象的使用。

带名称的伴生对象

伴生对象可以有名称,这在实现接口或扩展类时很有用。名称出现在 companion 关键字之后。

NamedCompanion.kt
package com.zetcode

interface Factory<T> {
    fun create(): T
}

class MyClass {
    companion object Named : Factory<MyClass> {
        override fun create(): MyClass = MyClass()
        fun hello() = println("Hello from companion")
    }
}

fun main() {

    val instance = MyClass.create()
    MyClass.hello() // Output: Hello from companion
}

此示例显示了一个实现 Factory 接口的带名称的伴生对象。名称 Named 允许我们在需要时显式引用伴生对象类型,同时仍然提供类级别的访问。

伴生对象属性

伴生对象可以保存类级别的属性,这些属性维护状态。这些属性在加载类时被初始化,并在所有实例之间共享。

CompanionProperties.kt
package com.zetcode

class Counter {
    companion object {
        private var count = 0
        fun increment() = ++count
        fun currentCount() = count
    }
}

fun main() {

    Counter.increment()
    Counter.increment()
    println(Counter.currentCount()) // Output: 2
}

Counter 类使用伴生对象在所有实例中维护一个计数。count 属性对伴生对象是私有的,显示了伴生对象如何封装类级别的状态。

伴生对象作为工厂

伴生对象通常用于实现工厂模式,提供创建实例的替代方法,同时隐藏构造函数细节。

FactoryCompanion.kt
package com.zetcode

class User private constructor(val name: String) {
    companion object {
        fun create(name: String): User {
            return User(name.trim())
        }
        
        fun createAdmin(): User {
            return User("Admin")
        }
    }
}

fun main() {

    val user = User.create(" John ")
    val admin = User.createAdmin()
    
    println(user.name) // Output: John
    println(admin.name) // Output: Admin
}

在这里,User 构造函数是私有的,强制通过伴生对象的工厂方法创建。这允许预处理(例如修剪)并提供命名的构造函数(createAdmin)以提高可读性。

伴生对象扩展

扩展函数可以添加到伴生对象中,从而提供可以在类名上调用的附加功能。

CompanionExtensions.kt
package com.zetcode

class MyClass {
    companion object
}

fun MyClass.Companion.hello() = println("Hello from extension")

fun main() {

    MyClass.hello() // Output: Hello from extension
}

此示例向 MyClass 的伴生对象添加了一个扩展函数。该函数直接在类名上调用。注意当伴生对象未命名时的 Companion 默认名称。

带有常量的伴生对象

伴生对象是定义与类相关的常量的理想选择,提供了比顶级常量更好的组织方式。

CompanionConstants.kt
package com.zetcode

class Color {
    companion object {
        const val RED = "#FF0000"
        const val GREEN = "#00FF00"
        const val BLUE = "#0000FF"
        
        fun allColors() = listOf(RED, GREEN, BLUE)
    }
}

fun main() {

    println(Color.RED) // Output: #FF0000
    println(Color.allColors()) // Output: [#FF0000, #00FF00, #0000FF]
}

Color 类在其伴生对象中将相关的颜色常量分组在一起。const val 使这些成为编译时常量。伴生对象还提供了实用方法,例如 allColors

用于接口实现的伴生对象

伴生对象可以实现接口,允许类在类级别提供接口功能,而无需创建实例。

InterfaceCompanion.kt
package com.zetcode

interface Logger {
    fun log(message: String)
}

class MyClass {
    companion object : Logger {
        override fun log(message: String) {
            println("LOG: $message")
        }
    }
}

fun main() {

    MyClass.log("Test message") // Output: LOG: Test message
}

在这里,伴生对象实现了 Logger 接口,允许直接在类名上调用日志记录功能。这种模式对于不需要实例状态的实用功能很有用。

伴生对象的最佳实践

来源

Kotlin 伴生对象文档

本教程深入介绍了 Kotlin 的 companion 关键字,展示了如何创建和使用伴生对象用于各种目的。我们探讨了工厂模式、常量、接口实现和扩展。伴生对象提供了一种强大的方式来组织 Kotlin 中的类级别功能。

作者

我的名字是 Jan Bodnar,我是一位热情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1400 多篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

列出 所有 Kotlin 教程