Android: 深入理解 ‘companion object {}‘

Android: 深入理解 ‘companion object {}’

在这里插入图片描述

Kotlin是一种现代的、静态类型的编程语言,它在设计时充分考虑了开发者的生产力和代码的可读性。其中一个独特的特性就是companion object。在本篇博客中,我们将深入探讨这个特性,理解它的工作原理,以及如何在Android开发中使用它。

companion object是什么?

companion object是一个可以访问类的所有非私有成员(包括方法和属性)的对象。这个对象被称为这个类的伴生对象,它的行为类似于Java中的静态成员。

如何使用companion object

要创建一个companion object,我们需要在类中声明一个companion object块。这个块可以包含方法和属性,这些方法和属性可以在没有类实例的情况下被访问。

以下是一个简单的示例:

class MyClass {companion object {fun printHello() {println("Hello, World!")}}
}// 调用方法
MyClass.printHello()

在这个示例中,我们定义了一个名为MyClass的类,这个类有一个companion object。这个companion object包含一个printHello方法,我们可以直接通过类名来调用这个方法,而不需要创建类的实例。

companion object的优点

companion object的一个主要优点是它们允许我们在不实例化类的情况下访问类的成员。这使得我们可以在不创建对象的情况下使用类的功能,这在某些情况下可以提高效率。

companion object的限制

虽然companion object非常有用,但是它们也有一些限制。首先,一个类只能有一个companion object。其次,companion object不能访问它们所在类的实例成员。

在Android中使用companion object

在Android开发中,我们经常需要在不同的Activity或者Fragment之间传递数据。companion object可以帮助我们实现这一点。例如,我们可以在companion object中定义一个用于启动Activity的方法,这个方法接收必要的参数,并将它们放入Intent中。

以下是一个示例:

class DetailActivity : AppCompatActivity() {companion object {fun start(context: Context, itemId: String) {val intent = Intent(context, DetailActivity::class.java).apply {putExtra("ITEM_ID", itemId)}context.startActivity(intent)}}
}// 调用方法
DetailActivity.start(context, "item_id")

在这个示例中,我们定义了一个DetailActivity,它有一个companion object。这个companion object有一个start方法,这个方法接收一个Context和一个itemId,并用它们来创建一个Intent。然后,它使用这个Intent来启动DetailActivity

静态成员和companion object

在Java中,我们可以声明静态成员——这些成员可以在没有类实例的情况下被访问。然而,在Kotlin中,没有静态成员的概念。取而代之的是companion object

companion object是Kotlin的一个特性,它允许我们在不创建类实例的情况下访问类的成员。这个功能在Java中是通过静态成员实现的,但在Kotlin中,我们使用companion object来实现。

companion object和Java互操作性

Kotlin是与Java完全互操作的,这意味着我们可以在Kotlin代码中调用Java代码,反之亦然。然而,companion object在Java代码中的表现形式并不直观。

当我们在Java代码中调用companion object的成员时,我们需要使用Companion关键字。例如,如果我们有一个Kotlin类MyClass,它有一个companion object,这个companion object有一个printHello方法,那么我们在Java代码中调用这个方法的方式如下:

MyClass.Companion.printHello();

companion object的内部工作原理

companion object的工作原理是通过创建一个包含静态成员的内部类来实现的。当我们在companion object中定义一个成员时,Kotlin编译器会在内部类中生成一个相应的静态成员。

这就是为什么我们可以在没有类实例的情况下访问companion object的成员,因为它们实际上是静态的。

companion object的更多细节

在我们深入了解companion object的基本用法之后,让我们更深入地探讨一些细节。在Kotlin中,companion object实际上是一个单例对象,它在类加载时就被初始化。

这意味着,不论我们创建了多少个类的实例,companion object都只有一个,它的所有成员都是静态的。这就是为什么我们可以在没有类实例的情况下访问companion object的成员。

companion objectobject的区别

在Kotlin中,除了companion object,我们还可以使用object关键字来创建单例对象。然而,objectcompanion object有一些重要的区别。

首先,object是一个完全独立的对象,它不属于任何类。而companion object是一个类的一部分,它可以访问类的所有非私有成员。

其次,object在定义时就被初始化,而companion object在类加载时被初始化。

最后,我们可以为object定义名字,但是companion object的名字总是Companion

companion object和工厂方法

companion object的另一个常见用途是实现工厂方法。工厂方法是一种创建对象的方法,它可以返回一个类的实例,或者返回一个实现了特定接口的类的实例。

以下是一个示例:

interface Animal {fun makeSound(): String
}class Dog : Animal {override fun makeSound() = "Woof!"
}class Cat : Animal {override fun makeSound() = "Meow!"
}class AnimalFactory {companion object {fun createAnimal(type: String): Animal = when (type) {"Dog" -> Dog()"Cat" -> Cat()else -> throw IllegalArgumentException("Unknown type")}}
}// 使用工厂方法
val dog = AnimalFactory.createAnimal("Dog")
val cat = AnimalFactory.createAnimal("Cat")
println(dog.makeSound()) // 输出 "Woof!"
println(cat.makeSound()) // 输出 "Meow!"

在这个示例中,我们定义了一个Animal接口和两个实现了这个接口的类:DogCat。然后,我们定义了一个AnimalFactory,它有一个companion object。这个companion object有一个createAnimal方法,这个方法根据传入的类型创建一个Animal的实例。

@JvmStatic注解

在Java代码中调用companion object的成员时,我们需要使用Companion关键字,这可能会导致代码看起来有些冗长。为了解决这个问题,我们可以使用@JvmStatic注解。

@JvmStatic注解告诉Kotlin编译器,我们希望在Java代码中像调用静态方法一样调用这个方法。当我们在companion object的成员上使用@JvmStatic注解时,我们可以直接通过类名来调用这个成员,而不需要使用Companion关键字。

以下是一个示例:

class MyClass {companion object {@JvmStatic fun printHello() {println("Hello, World!")}}
}

在这个示例中,我们在printHello方法上使用了@JvmStatic注解。这意味着我们可以在Java代码中通过MyClass.printHello()来调用这个方法。

companion object和延迟初始化

在某些情况下,我们可能希望延迟companion object的初始化。例如,我们可能有一个companion object,它需要一个配置对象来初始化,但是这个配置对象在类加载时可能还不可用。

在这种情况下,我们可以使用by lazy来延迟初始化companion objectby lazy是Kotlin的一个委托属性,它可以让我们在第一次访问属性时才初始化它。

以下是一个示例:

class MyClass {companion object {val config: Config by lazy {loadConfig()}private fun loadConfig(): Config {// Load the config objectreturn Config()}}
}

在这个示例中,我们在companion object中定义了一个config属性,这个属性使用by lazy来延迟初始化。config属性在第一次被访问时,会调用loadConfig方法来加载配置对象。

companion object和单例模式

companion object和单例模式有很多相似之处,但是它们并不完全相同。单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点来访问这个实例。

在Kotlin中,我们可以使用object关键字来实现单例模式。然而,companion object并不是一个真正的单例,因为它们是类的一部分,而不是一个独立的实例。

尽管如此,companion object在许多情况下都可以作为单例模式的替代方案,特别是当我们需要在没有类实例的情况下访问类的成员时。

companion object@JvmField注解

@JvmStatic注解类似,@JvmField注解也可以让我们在Java代码中更方便地访问companion object的成员。当我们在companion object的成员上使用@JvmField注解时,我们可以直接通过类名来访问这个成员,而不需要使用Companion关键字。

以下是一个示例:

class MyClass {companion object {@JvmField val HELLO = "Hello, World!"}
}

在这个示例中,我们在HELLO属性上使用了@JvmField注解。这意味着我们可以在Java代码中通过MyClass.HELLO来访问这个属性。

companion object和匿名内部类

companion object和Java中的匿名内部类有一些相似之处。在Java中,我们可以使用匿名内部类来创建一个没有名字的类,并立即创建它的一个实例。在Kotlin中,我们可以使用companion object来达到类似的效果。

以下是一个示例:

interface MyInterface {fun printHello()
}class MyClass {companion object : MyInterface {override fun printHello() {println("Hello, World!")}}
}

在这个示例中,MyClasscompanion object实现了MyInterface接口。这意味着我们可以通过MyClass来访问MyInterface的所有成员。

companion object和构造函数

在Kotlin中,我们可以在companion object中定义一个名为invoke的方法,这个方法可以让我们像调用构造函数一样调用companion object

以下是一个示例:

class MyClass {companion object {operator fun invoke() {println("Companion object is invoked!")}}
}// 调用 `companion object`
MyClass() // 输出 "Companion object is invoked!"

在这个示例中,MyClasscompanion object定义了一个invoke方法。这意味着我们可以像调用构造函数一样调用MyClass

companion object和扩展函数

我们可以为companion object定义扩展函数。这可以让我们增加companion object的功能,而不需要修改原始类的代码。

以下是一个示例:

class MyClass {companion object {}
}// 定义扩展函数
fun MyClass.Companion.printHello() {println("Hello, World!")
}// 使用扩展函数
MyClass.printHello() // 输出 "Hello, World!"

在这个示例中,我们为MyClasscompanion object定义了一个扩展函数printHello。我们可以通过类名来调用这个函数。

companion object和扩展属性

除了扩展函数,我们还可以为companion object定义扩展属性。扩展属性可以让我们增加companion object的功能,而不需要修改原始类的代码。

以下是一个示例:

class MyClass {companion object {}
}// 定义扩展属性
var MyClass.Companion.extraData: Stringget() = "Extra data"set(value) { println("Setting extra data to $value") }// 使用扩展属性
println(MyClass.extraData) // 输出 "Extra data"
MyClass.extraData = "New data" // 输出 "Setting extra data to New data"

在这个示例中,我们为MyClasscompanion object定义了一个扩展属性extraData。我们可以通过类名来访问和修改这个属性。

结语

在这篇博客中,我们深入探讨了Kotlin中companion object的各个关键方面。我们讨论了companion object如何与@JvmField注解、匿名内部类、构造函数以及扩展函数一起工作。这些知识将帮助我们更好地理解和使用Kotlin中的companion object,从而提升我们的编程效率和代码质量。希望你从这篇博客中获得了有价值的信息,如果你有任何问题或者想要讨论更多关于companion object的话题,欢迎在评论区留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/669316.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java21 + SpringBoot3集成七牛云对象存储OSS,实现文件上传

文章目录 前言实现步骤引入maven依赖修改配置文件创建七牛云配置类创建文件操作服务类创建文件操作控制器前端实现运行效果 总结 前言 近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统&#xf…

EOF和0区别

题目描述 KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的X形图案。 输入描述: 多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜…

你的歌声婉转入云霄

可爱的一朵玫瑰花 - 吕继宏 可爱的一朵玫瑰花塞地玛丽亚 可爱的一朵玫瑰花塞地玛丽亚 那天我在山上打猎骑着马(人善被人欺马善被人骑) 正当你在山下歌唱婉转入云霄 歌声使我迷了路 我从山坡滚下 哎呀呀 你的歌声婉转入云霄 强壮的青年哈萨克伊万杜达尔 …

【八大排序】选择排序 | 堆排序 + 图文详解!!

📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构冒险记 ✅C语言进阶之路 🌅 有航道的人,再渺小也不会迷途。 文章目录 一、选择排序1.1 基本思想1.2 算法步骤 动图演示1.3 代码实现1.4 选择排序特性总结 二…

C/C++内存管理的底层调用逻辑

✨Blog:🥰不会敲代码的小张:)🥰 🉑推荐专栏:C语言🤪、Cpp😶‍🌫️、数据结构初阶💀 💽座右铭:“記住,每一天都是一個新的開始&#x1…

【TCP/IP】用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时,网络上的每一层都会涉及不同的协议,具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例: 物理层:负责将比特流传输到物理媒介上,例如电缆或无线信号。所以在物理层,可…

vue3项目实现预览图片、旋转图片功能

一、需求: 在点击图片时,能预览大图,弹出一个包含旋转图片功能按钮的弹窗。用户可通过点击按钮实现对图片的旋转操作 二、思路: 点击图片预览: 用户通过点击图片触发预览功能。接收图片的 URL,弹出一个模…

【GameFramework框架】四、GameFramework框架内置模块

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录: https://blog.csdn.net/q7…

问题:下列关于海关统计项目的表述,正确的有:A.进出境货物的统计重量和数量应以报关单位申报的重量和数 #笔记#职场发展#媒体

问题:下列关于海关统计项目的表述,正确的有:A.进出境货物的统计重量和数量应以报关单位申报的重量和数 下列关于海关统计项目的表述,正确的有: A.进出境货物的统计重量和数量应以报关单位申报的…

echarts使用之地图(五)

1 基本使用 百度地图 API : 使用百度地图的 api , 它能够在线联网展示地图 , 百度地图需要申请 ak 矢量地图 : 可以离线展示地图 , 需要开发者准备矢量地图数据。本文使用该方式。 json格式的数据如下&#xff1a; 格式参照&#xff1a;GeoJSON <!DOCTYPE html&…

Java实现数据可视化的智慧河南大屏 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 数据模块 A4.2 数据模块 B4.3 数据模块 C4.4 数据模块 D4.5 数据模块 E 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数据可视化的智慧河南大屏&#xff0c;包含了GDP、…

泰克示波器(TBS2000系列)保存功能使用

目录 1.1 Save/Recall按钮1.2 保存动作1.3 文件格式1.4 保存 在使用示波器时&#xff0c;测量后的结果我们常常需要记录下来&#xff0c;大部分情况我们是拍照记录&#xff0c;单图像往往不清晰&#xff0c;这时使用示波器专用的保存功能&#xff0c;插入U盘即可保存&#xff0…

STM32--SPI通信协议(3)SPI通信外设

前言 硬件SPI&#xff1a;通过硬件电路实现&#xff0c;所以硬件SPI速度更快&#xff0c;有专门的寄存器和 库函数 &#xff0c;使用起来更方便。 软件SPI&#xff1a;也称模拟SPI&#xff0c;通过程序控制IO口电平模拟SPI时序实现&#xff0c;需要程序不断控制IO电平翻转&am…

JAVA字节流的两个重要子类FileOutputStream、FileInputStream

字节流&#xff0c;字符集&#xff0c;字符流 因为它们都是抽象类&#xff0c;所以要学习它们的子类 字节流的结构: FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写入本地文件。 书写步骤&#xff1a; 创建字节输出流对象写数据释放资源 演示:…

C语言开发单片机为什么大多数都采用全局变量的形式?

C语言开发单片机为什么大多数都采用全局变量的形式&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&…

STM32F4学习

F4系统架构 8个主控总线7个被控总线 主控总线 Cortex-M4内核 I总线Cortex-M4内核 D总线Cortex-M4内核 S总线DMA1存储器总线DMA2存储器总线DMA2外设总线以太网DMA总线USB OTG HS DMA总线 被控总线 内部FLASH ICode总线内部FLASH DCode总线主要内部SRAM1&#xff08;112KB&a…

【AI绘画+Midjourney平替】Fooocus:图像生成、修改软件(Controlnet原作者重新设计的UI+Windows一键部署)

代码&#xff1a;https://github.com/lllyasviel/Fooocus windows一键启动包下载&#xff1a;https://github.com/lllyasviel/Fooocus/releases/download/release/Fooocus_win64_2-1-831.7z B站视频教程&#xff1a;AI绘画入门神器&#xff1a;Fooocus | 简化SD流程&#xff0c…

【51单片机】开发板&开发软件(Keil5&STC-ISP)简介&下载安装破译传送门(1)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

Windows如何安装Node.js环境并制作贪吃蛇小游戏分享好友远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…

redis(6)

文章目录 一、redis clusterRedis Cluster 工作原理Redis cluster 基本架构Redis cluster主从架构Redis Cluster 部署架构说明部署方式介绍 原生命令手动部署原生命令实战案例&#xff1a;利用原生命令手动部署redis cluster 实战案例&#xff1a;基于Redis 5 的redis cluster部…