1. 概述
在 Kotlin 中,当我们需要定义一些不依赖类实例的类级成员时,通常会使用 Companion Object。Kotlin 编译器会确保每个类中最多只有一个 Companion Object 实例。对于熟悉 Java 或 C# 的开发者来说,Companion Object 类似于 static
成员的实现方式。
例如,在实现工厂模式(如静态工厂方法或抽象工厂)时,Companion Object 就非常有用,因为它可以作为类的“静态上下文”来集中管理对象的创建逻辑。
2. 声明 Companion Object
Companion Object 的声明方式如下:
class ClassName {
companion object {
const val propertyName: String = "Something..."
fun funName() {
//...
}
}
}
在类名后直接通过 .属性名
或 .方法名()
的方式调用:
val property = ClassName.propertyName
ClassName.funName()
同时,在类内部也可以直接访问这些成员,无需加类名:
class ClassName {
fun anotherFun() {
println(propertyName)
}
companion object {
const val propertyName: String = "Something..."
fun funName() {
//...
}
}
}
✅ 注意: Companion Object 成员会在首次被调用时初始化,且是在其所属类的实例化之后完成初始化。
3. 命名 Companion Object
默认情况下,Companion Object 的名字是 Companion
,但我们也可以给它起一个更具有语义化的名字,比如 Factory
、Utils
等。
以工厂方法模式为例,我们可以通过命名 Companion Object 来提升代码可读性:
class MyClass {
companion object Factory {
fun createInstance(): MyClass = MyClass()
}
}
调用时可以使用类名 + Companion 名字的方式:
val instance = MyClass.Factory.createInstance()
❌ 注意: 每个类只能有一个 Companion Object,不能定义多个。
4. 继承与 Companion Object
Companion Object 不能被继承,但它可以继承其他类或实现接口。这使得它在某些场景下比 Java 的 static
更灵活。
举个例子,我们可以利用这个特性来实现抽象工厂模式(Abstract Factory Pattern):
首先定义接口和抽象类:
interface Theme {
fun someFunction(): String
}
abstract class FactoryCreator {
abstract fun produce(): Theme
}
然后分别实现两个具体的类和它们的 Companion Object:
class FirstRelatedClass : Theme {
companion object Factory : FactoryCreator() {
override fun produce() = FirstRelatedClass()
}
override fun someFunction(): String {
return "I am from the first factory."
}
}
class SecondRelatedClass : Theme {
companion object Factory : FactoryCreator() {
override fun produce() = SecondRelatedClass()
}
override fun someFunction(): String {
return "I am from the second factory."
}
}
最后在 main
函数中使用抽象工厂:
fun main() {
val factoryOne: FactoryCreator = FirstRelatedClass.Factory
println(factoryOne.produce().someFunction())
val factoryTwo: FactoryCreator = SecondRelatedClass.Factory
println(factoryTwo.produce().someFunction())
}
这篇文章详细解释了 Kotlin 中的抽象工厂模式。
5. Java 互操作性
虽然 Kotlin 的 Companion Object 可以继承类和接口,但在 Java 中无法直接访问这些特性。为了在 Java 中更好地使用这些成员,我们需要使用 @JvmStatic
注解。
例如:
class MyClass {
companion object {
@JvmStatic
val propertyName: String = "Something..."
}
}
这样在 Java 中就可以像调用静态字段一样访问它:
MyClass.propertyName;
更多内容可以参考:在 Java 中访问 Kotlin 的 Companion Object
6. 接口中的 Companion Object
Kotlin 的接口也可以包含 Companion Object。这在定义常量或辅助函数时非常有用,特别是这些常量或函数与接口本身语义相关时。
例如:
interface MyInterface {
companion object {
const val PROPERTY = "value"
}
}
这样我们就可以直接通过接口名访问:
println(MyInterface.PROPERTY)
7. 总结
Companion Object 是 Kotlin 中用于定义类级成员的重要机制。它不仅提供了类似 Java 中 static
的功能,还支持继承和接口实现,大大增强了其灵活性。
本文涉及的代码示例均可在 GitHub 仓库 找到。