Kotlin 中 companion object 扩展函数和普通函数区别

发布于:2025-06-03 ⋅ 阅读:(20) ⋅ 点赞:(0)

在 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 扩展函数
  • 需要 操作具体实例数据 → 用普通成员函数
  • 需要 为无法修改的类添加功能 → 用普通扩展函数


网站公告

今日签到

点亮在社区的每一天
去签到