当前位置: 首页 > ai >正文

Kotlin伴生对象

你已经知道如何为类创建单例对象(singleton)。不过,在很多情况下,你只需要为某个类维护一个单例,这时候使用类的完整名字会显得冗长。比如,你可能只需要存储一个公共的属性。这种情况下,可以用 Kotlin 的另一个特性 —— companion object(伴生对象)


伴生对象(Companion object)

在一个类内部,可以声明一个用 companion 关键字标记的对象:

class Player(val id: Int) {companion object Properties {/* 默认玩家速度 - 每回合移动 7 格 */val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int {/* 计算移动速度的惩罚 */}}
}/* 输出 7 */
println(Player.Properties.defaultSpeed)

解释:
伴生对象是绑定在外部类上的单例,必须通过外部类访问它。它表明该对象与外部类有紧密联系。比如,可以把所有玩家的默认速度存在 Player 类的伴生对象里。每个 Player 实例都会持有伴生对象的引用,访问时都会得到这个唯一实例。


省略伴生对象名字

我们也可以不给伴生对象命名,这样访问时更加简洁:

class Player(val id: Int) {companion object {val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int {/* 计算移动惩罚 */}}
}/* 输出 7 */
println(Player.defaultSpeed)

解释:
省略名字后,仍然可以通过外部类直接访问伴生对象的成员。如果需要,也可以用默认名字 Companion 访问:

/* 依然输出 7 */
println(Player.Companion.defaultSpeed)

伴生对象与外部类

伴生对象与外部类联系非常紧密。在外部类中,可以直接使用伴生对象的属性和方法:

class Deck {companion object {val size = 10val height = 2fun volume(bottom: Int, height: Int) = bottom * height}val square = size * size             // 100val volume = volume(square, height)  // 200
}

同名属性的遮蔽(Shadowing)

如果外部类中有与伴生对象同名的属性,会“遮蔽”伴生对象的同名属性:

class Deck {companion object {val size = 10}val size = 2val square = size * size // 4,使用的是外部类的 size
}

如果想访问伴生对象的 size,需要明确使用伴生对象的名字:

class Deck {companion object {val size = 10}val size = 2val square = Companion.size * Companion.size // 100
}

伴生对象不能访问外部类实例成员

和嵌套对象类似,伴生对象不能访问外部类的实例属性和方法:

class Deck() {val size = 2object Properties {val defaultSize = size // 错误,无法访问外部类的实例变量}
}

伴生对象的限制

  • 每个类最多只能有一个伴生对象,即使起不同名字也不行:
class BadClass {companion object Properties {}companion object Factory {}
}
// 编译错误:每个类只能有一个伴生对象
  • 可以有一个伴生对象,同时拥有多个嵌套对象:
class Player(val id: Int) {companion object Properties {val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int {// ...}}object Factory {fun create(playerId: Int): Player {return Player(playerId)}}
}println(Player.Properties.defaultSpeed) // 7
println(Player.defaultSpeed)             // 7
println(Player.Factory.create(13).id)   // 13
  • 伴生对象不能定义在另一个单例对象或伴生对象内部,因为这会违反全局访问的原则:
object OuterSingleton {companion object InnerSingleton { // 编译错误,伴生对象不能嵌套在对象中}
}

与其他语言的对比

如果你来自其他语言,可能会觉得伴生对象有点陌生。它类似于 Java 或 C++ 中的 static 成员,static 表示成员属于类本身,而不是实例。比如,Java 中:

class Dog {public static int numOfPaws = 4;public static String createSound() {return "WUF-WUF";}
}/* 输出 WUF-WUF */
System.out.println(Dog.createSound());

Kotlin 没有 static 关键字,推荐用伴生对象来实现类似功能:

class Dog {companion object {val numOfPaws: Int = 4fun createSound(): String = "WUF-WUF"}
}/* 输出 WUF-WUF */
println(Dog.createSound())

总结

  • 伴生对象是和类紧密关联的单例对象。

  • 它是组织类级别数据和方法的好方式。

  • 在外部类中可以直接访问伴生对象的成员,反之则不行。

  • 每个类只能有一个伴生对象。

  • 它是 Kotlin 中实现类静态成员的推荐做法。

http://www.xdnf.cn/news/15981.html

相关文章:

  • Kotlin 作用域函数 let 的实现原理
  • 什么是检索增强生成(RAG)?
  • 深入浅出控制反转与依赖注入:从理论到实践
  • 社交电商推客系统全栈开发指南:SpringCloud+分润算法+Flutter跨端
  • 深度学习篇---车道线循迹
  • CMake实践:CMake3.30版本之前和之后链接boost的方式差异
  • Pulsar存储计算分离架构设计之Broker无状态
  • linux: tar解压之后属主和属组不是当前用户问题
  • [c++11]constexpr
  • MCP消息协议和传输协议(Java角度)
  • 【数学建模|Matlab】Matlab「基础知识」和「基础操作」
  • es搜索实现既能模糊查询又能分词查询
  • Linux部署.net Core 环境
  • 8.4 Java 原生 TCP Socket 实现 HTTP 请求解析和请求分发
  • Dify接入MCP案例1:基于Chatflow旅行、吃饭、新闻、学习的AI智能体
  • 公司内部网址怎么在外网打开?如何让外网访问内网的网站呢?
  • 2025 年非关系型数据库全面指南:类型、优势
  • cddlib(用于凸多面体计算和线性不等式系统求解)的开源库
  • JAVA API (三):从基础爬虫构建到带条件数据提取 —— 详解 URL、正则与爬取策略
  • Java 大视界 -- Java 大数据在智能交通自动驾驶车辆与周边环境信息融合与决策中的应用(357)
  • JMeter 实现 Protobuf 加密解密
  • UE5 UI 水平框
  • ansible 批量 scp 和 load 镜像
  • MybatisPlus-16.扩展功能-枚举处理器
  • Windows PE文件内未用空间学习
  • DNS应用层协议
  • Linux驱动-中断-共享队列
  • 两个android,一个客户端一个服务器端
  • 2025.7.22 测试 总结
  • Web服务器(Tomcat、项目部署)