在 Kotlin 中,companion object
的扩展函数与普通函数(包括普通成员函数和普通扩展函数)有显著区别。以下是它们的核心差异和适用场景:
1. 定义位置与归属
特性 | companion object 扩展函数 | 普通函数 |
---|
定义位置 | 在类外部为伴生对象添加 | 在类内部(成员函数)或任意位置(扩展函数) |
归属关系 | 属于类的伴生对象,而非类实例 | 成员函数属于实例,普通扩展函数属于接收者类型 |
示例对比:
// companion object 扩展函数
class MyClass {companion object
}
fun MyClass.Companion.extFunc() = println("扩展函数")// 普通成员函数
class MyClass {fun memberFunc() = println("成员函数")
}// 普通扩展函数(非伴生对象)
fun MyClass.extFunc() = println("普通扩展函数")
2. 调用方式
特性 | companion object 扩展函数 | 普通函数 |
---|
调用主体 | 通过类名直接调用 | 成员函数需实例,普通扩展函数通过实例调用 |
语法 | ClassName.func() | instance.func() |
示例对比:
// companion object 扩展函数
MyClass.extFunc() // 直接通过类名调用// 普通成员函数
val obj = MyClass()
obj.memberFunc() // 需要实例// 普通扩展函数
obj.extFunc() // 需要实例
3. 访问权限
特性 | companion object 扩展函数 | 普通函数 |
---|
访问私有成员 | 只能访问伴生对象的私有成员 | 成员函数可访问类所有成员,普通扩展函数只能访问公有成员 |
上下文 | 无类实例上下文(相当于静态上下文) | 普通成员函数有 this 指向实例 |
示例对比:
class MyClass(private val secret: String) {companion object {private const val COMPANION_SECRET = "companion-secret"}fun memberFunc() {println(secret) // 可访问实例私有属性println(COMPANION_SECRET) // 可访问伴生对象私有属性}
}// companion object 扩展函数
fun MyClass.Companion.extFunc() {println(COMPANION_SECRET) // 只能访问伴生对象的私有成员// println(secret) // 编译错误:无法访问实例成员
}// 普通扩展函数
fun MyClass.extFunc() {// println(secret) // 编译错误:无法访问私有成员// println(COMPANION_SECRET) // 编译错误:无法访问伴生对象私有成员
}
4. 使用场景
场景 | companion object 扩展函数 | 普通函数 |
---|
工具类方法 | ✅ 适合(如 StringUtils.parse() ) | ❌ 需实例,不直观 |
工厂模式 | ✅ 通过类名创建对象(MyClass.create() ) | ❌ 需先有工厂实例 |
实例操作 | ❌ 无法操作实例 | ✅ 主要用途 |
第三方库扩展 | ✅ 为已有类添加静态方法 | ✅ 为实例添加方法 |
典型用例:
// companion object 扩展:为 Android 的 Toast 添加静态方法
fun Toast.Companion.showShort(context: Context, text: String) {makeText(context, text, Toast.LENGTH_SHORT).show()
}
// 调用:Toast.showShort(context, "Hello")// 普通扩展:为 String 添加功能
fun String.addExclamation() = "$this!"
// 调用:"Hi".addExclamation()
5. 初始化时机
特性 | companion object 扩展函数 | 普通函数 |
---|
加载时机 | 首次访问类时初始化伴生对象 | 随实例创建或调用时执行 |
内存开销 | 类级别共享 | 实例级别(成员函数)或无状态(扩展函数) |
总结对比表
维度 | companion object 扩展函数 | 普通成员函数 | 普通扩展函数 |
---|
定义位置 | 类外部 | 类内部 | 任意位置 |
调用方式 | ClassName.func() | instance.func() | instance.func() |
访问权限 | 仅伴生对象成员 | 全实例成员 | 仅公有成员 |
典型用途 | 静态工具方法、工厂模式 | 实例行为封装 | 增强已有类功能 |
内存分配 | 类级别(单次初始化) | 每实例占用 | 无状态(不占内存) |
选择建议
- 需要 通过类名直接调用 且 不依赖实例状态 → 用
companion object
扩展函数 - 需要 操作具体实例数据 → 用普通成员函数
- 需要 为无法修改的类添加功能 → 用普通扩展函数