目录

Kotlin 伴生对象(Companion Object)详解 —— 使用指南

伴生对象是Kotlin中一个独特且强大的特性,它提供了类级别的功能和属性,同时保持了与Java的良好互操作性。

一、概念与基本使用

1.1 什么是伴生对象

伴生对象是声明在类内部的对象,用companion object关键字标记。它与外部类关联,可以访问类的私有成员,相当于类的"静态"成员容器。

kotlin 复制代码
class MyClass {
    companion object {
        const val CONSTANT = "Constant Value"
        
        fun create(): MyClass = MyClass()
    }
}

1.2 基本用法

kotlin 复制代码
class DatabaseClient {
    companion object {
        private var instance: DatabaseClient? = null
        
        fun getInstance(): DatabaseClient {
            if (instance == null) {
                instance = DatabaseClient()
            }
            return instance!!
        }
    }
    
    fun connect() { println("Connected") }
}

fun main() {
    // 通过类名直接访问伴生对象成员
    val client = DatabaseClient.getInstance()
    client.connect()
}

二、使用场景

2.1 替代Java静态成员

kotlin 复制代码
class MathUtils {
    companion object {
        fun add(a: Int, b: Int) = a + b
        const val PI = 3.14159
    }
}

fun main() {
    println(MathUtils.add(2, 3))  // 5
    println(MathUtils.PI)         // 3.14159
}

2.2 工厂方法

kotlin 复制代码
class User private constructor(val name: String) {
    companion object {
        fun create(name: String): User {
            return User(name.trim())
        }
        
        fun createWithDefault(): User {
            return User("Guest")
        }
    }
}

fun main() {
    val user1 = User.create("Alice")
    val user2 = User.createWithDefault()
}

2.3 实现接口

kotlin 复制代码
interface Factory<T> {
    fun create(): T
}

class MyClass {
    companion object : Factory<MyClass> {
        override fun create(): MyClass {
            return MyClass()
        }
    }
}

fun <T> createInstance(factory: Factory<T>): T {
    return factory.create()
}

fun main() {
    val instance = createInstance(MyClass)
}

三、高级特性

3.1 伴生对象名称

可以为伴生对象指定名称,未指定时默认名称为Companion

kotlin 复制代码
class MyClass {
    companion object Named {
        fun method() { println("Named companion") }
    }
}

fun main() {
    MyClass.Named.method()  // 使用名称访问
    MyClass.method()        // 也可以直接访问
}

3.2 扩展函数

可以为伴生对象定义扩展函数:

kotlin 复制代码
class MyClass {
    companion object
}

fun MyClass.Companion.extensionFunc() {
    println("Extension function on companion")
}

fun main() {
    MyClass.extensionFunc()
}

3.3 伴生对象中的属性

kotlin 复制代码
class Configuration {
    companion object {
        private var _version: String = "1.0"
        
        var version: String
            get() = _version
            set(value) { _version = value }
            
        val buildNumber: Int by lazy { 
            // 复杂初始化
            Random.nextInt(1000) 
        }
    }
}

fun main() {
    println(Configuration.version)  // 1.0
    Configuration.version = "2.0"
    println(Configuration.buildNumber)
}

四、与Java互操作

4.1 从Java访问伴生对象

Kotlin伴生对象在Java中表现为一个名为Companion的静态字段(如果伴生对象有名称,则使用该名称)。

java 复制代码
// Java代码
public class JavaClient {
    public static void main(String[] args) {
        // 访问Kotlin伴生对象
        MyClass.Companion.method();
        
        // 如果伴生对象有名称
        // MyClass.Named.method();
        
        // 对于const val属性
        String constant = MyClass.CONSTANT;
    }
}

4.2 使用@JvmStatic和@JvmField优化

为了使Kotlin伴生对象成员在Java中更像静态成员,可以使用注解:

kotlin 复制代码
class KotlinClass {
    companion object {
        @JvmStatic
        fun staticMethod() { println("Static method") }
        
        @JvmField
        val staticField = "Static Field"
        
        const val CONSTANT = "Constant"
    }
}

在Java中使用:

java 复制代码
// Java代码
public class JavaClient {
    public static void main(String[] args) {
        KotlinClass.staticMethod();  // 可以直接调用
        String field = KotlinClass.staticField;  // 直接访问字段
        String constant = KotlinClass.CONSTANT;  // const val自动为静态
    }
}

4.3 伴生对象实现接口时的Java互操作

kotlin 复制代码
interface Logger {
    fun log(message: String)
}

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

// Java中使用
public class JavaClient {
    public static void main(String[] args) {
        MyClass.Companion.log("Message from Java");
    }
}

五、注意事项

5.1 伴生对象的初始化时机

伴生对象在对应的类被加载时初始化(通常是第一次访问时),且只初始化一次。

kotlin 复制代码
class InitializationDemo {
    companion object {
        init {
            println("Companion object initialized")
        }
        
        fun method() { println("Method called") }
    }
}

fun main() {
    println("Before access")
    InitializationDemo.method()  // 此时伴生对象才会初始化
}

5.2 伴生对象与对象表达式的区别

  • 伴生对象是类级别的单例,与类关联
  • 对象表达式是立即执行的匿名对象
kotlin 复制代码
class MyClass {
    companion object {
        // 类级别的单例
    }
    
    fun createAnonymousObject(): Any {
        return object {
            // 每次调用都会创建新实例
            val prop = 42
        }
    }
}

5.3 继承中的伴生对象

伴生对象不会被继承,每个类都有自己的伴生对象实例。

kotlin 复制代码
open class Parent {
    companion object {
        fun method() { println("Parent companion") }
    }
}

class Child : Parent() {
    companion object {
        fun method() { println("Child companion") }
    }
}

fun main() {
    Parent.method()  // Parent companion
    Child.method()   // Child companion
}

5.4 性能考虑

伴生对象中的属性和方法不是真正的静态成员(除非使用@JvmStatic),访问时会有轻微的性能开销。

六、实际应用示例

6.1 单例模式

kotlin 复制代码
class Singleton private constructor() {
    companion object {
        @Volatile private var instance: Singleton? = null
        
        fun getInstance(): Singleton {
            return instance ?: synchronized(this) {
                instance ?: Singleton().also { instance = it }
            }
        }
    }
    
    fun doWork() { println("Working...") }
}

fun main() {
    Singleton.getInstance().doWork()
}

6.2 构建器模式

kotlin 复制代码
class Car private constructor(
    val model: String,
    val color: String,
    val year: Int
) {
    companion object Builder {
        private var model: String = ""
        private var color: String = "Black"
        private var year: Int = 2023
        
        fun model(model: String) = apply { this.model = model }
        fun color(color: String) = apply { this.color = color }
        fun year(year: Int) = apply { this.year = year }
        
        fun build(): Car {
            require(model.isNotEmpty()) { "Model must be specified" }
            return Car(model, color, year)
        }
    }
}

fun main() {
    val car = Car.Builder
        .model("Tesla")
        .color("Red")
        .year(2022)
        .build()
    
    println("${car.model} ${car.color} ${car.year}")
}

6.3 工具类

kotlin 复制代码
class StringUtils {
    companion object {
        fun isPalindrome(s: String): Boolean {
            return s == s.reversed()
        }
        
        fun capitalize(s: String): String {
            return s.replaceFirstChar { it.uppercase() }
        }
    }
}

fun main() {
    println(StringUtils.isPalindrome("madam"))  // true
    println(StringUtils.capitalize("hello"))    // Hello
}

七、总结

  1. 概念:伴生对象是类内部的特殊对象,与类关联,可以访问类的私有成员

  2. 基本使用 :通过companion object声明,通过类名直接访问成员

  3. 使用场景

    • 替代Java静态成员
    • 实现工厂模式
    • 创建工具类
    • 实现接口
  4. 高级特性

    • 可命名伴生对象
    • 支持扩展函数
    • 可以包含属性和复杂逻辑
  5. Java互操作

    • 通过Companion字段访问
    • 使用@JvmStatic@JvmField优化
  6. 注意事项

    • 初始化时机
    • 与对象表达式的区别
    • 继承行为
    • 性能考虑

伴生对象是Kotlin中非常灵活的特性,合理使用可以使代码更加简洁、表达力更强,同时保持与Java的良好互操作性。

更多分享

  1. 一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)
  2. 一文带你吃透Kotlin协程的launch()和async()的区别
  3. Kotlin 委托与扩展函数------新手入门
  4. Kotlin 作用域函数(let、run、with、apply、also)的使用指南
  5. 一文带你吃透Kotlin中 lateinit 和 by lazy 的区别和用法
  6. Kotlin 扩展方法(Extension Functions)使用详解
  7. Kotlin 中 == 和 === 的区别
  8. Kotlin 操作符与集合/数组方法详解------新手指南
  9. Kotlin 中 reified 配合 inline 不再被类型擦除蒙蔽双眼
  10. Kotlin Result 类型扩展详解 ------ 新手使用指南
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
决胜万里6 小时前
Android WIFI体系
android
0wioiw06 小时前
安卓基础(无障碍点击)
android
阿达C9 小时前
MySQL常用函数详解及SQL代码示例
android·sql·mysql
缘来的精彩11 小时前
Android Studio 中实现方法和参数显示一行
android·ide·android studio
二七有头发11 小时前
从零开始:Android Studio开发购物车(第二个实战项目)
android·ide·android studio
我命由我1234511 小时前
MQTT - Android MQTT 编码实战(MQTT 客户端创建、MQTT 客户端事件、MQTT 客户端连接配置、MQTT 客户端主题)
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
奔跑吧 android12 小时前
【android bluetooth 协议分析 06】【l2cap详解 11】【l2cap连接超时处理逻辑介绍】
android·bluetooth·l2cap·gd·aosp13
MyhEhud15 小时前
kotlin flatMap 变换函数的特点和使用场景
开发语言·windows·kotlin
三思而后行,慎承诺15 小时前
Kotlin 常见问题
开发语言·面试·kotlin
百锦再18 小时前
Android Studio开发中Application和Activity生命周期详解
android·java·ide·app·gradle·android studio·studio