网站首页 > 博客文章 正文
object 关键字
Kotlin 中有一种特殊的类,它本身也是一个实例(单例),这种既是类又是对象的类需要使用 object 关键字声明(普通类声明使用 class),它跟普通类一样,也可以实现接口和继承父类:
object MusicPlayer : Player(), OnStatusChangeListener {
var state: Int = 0
fun play(url: String) {
...
}
fun stop() {
...
}
override fun onMount(driver: Driver) {
}
override fun onUnmount(driver: Driver) {
}
}
这种 object 类的方法可以通过类名直接调用:
fun main() {
MusicPlayer.play("http://qqmusic.com/123213.mp3")
MusicPlayer.stop()
}
借助 Show Kotlin Bytecode 工具,将上述 Kotlin 代码反编译成 java 代码如下:
public final class MusicPlayer extends Player implements OnStatusChangeListener {
public static final MusicPlayer INSTANCE;
private MusicPlayer() {
}
static {
MusicPlayer var0 = new MusicPlayer();
INSTANCE = var0;
}
...
}
可以发现,Kotlin 中的 object 本质上就是 Java 中简单的单例模式,同时它的构造方法是 private 的,因此 object 类不能自定义构造方法!
伴生对象(companion object)
日常开发中,经常会编写一些 Bean 类,用于描述一类事物,Bean 中会包含事物的属性,有的 Bean 类还会提供一系列"工具方法"来帮助开发者快速创建 Bean 对象,就比如在 Java 中,Integer.valueOf() 就可以帮助开发者快速将字符串转成整型,进入源码一看,可以发现这是一个使用了 static 关键字修饰的静态方法:
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
可是,在 Kotlin 中是没有 static 关键字的!!!想要实现通过 类名.xxx() 的方式调用工具方法,可以使用上述的 object 类,但 object 本身就是一个对象,我们无法在外部调用其构造方法,既然想拥有 object 类(通过类名调用方法)与 class 类(外部可以调用构造方法)的两种特性,这时伴生对象 companion object 就完全可以满足这个需求:
class Rectangle(val width: Int, val height: Int) {
companion object {
fun ofSize(width: Int, height: Int): Rectangle {
return Rectangle(width, height)
}
fun ofRectangle(rectangle: Rectangle): Rectangle {
return Rectangle(rectangle.width, rectangle.height)
}
}
}
fun main() {
val width = 4
val height = 5
val rectangle1 = Rectangle(width, height) // 调用构造方法
val rectangle2 = Rectangle.ofRectangle(rectangle1) // 通过类名调用方法
val rectangle3 = Rectangle.ofSize(width, height) // 通过类名调用方法
}
伴生对象顾名思义,就是与类一起诞生的对象,类一加载,它的伴生对象也就被创建了,每个类都可以对应一个伴生对象,并且该伴生对象的成员全局独一份,也就是说伴生对象 companion object 也是一种单例,再次借助 Show Kotlin Bytecode 工具,将上述 Kotlin 代码反编译成 java 代码如下:
public final class Rectangle {
...
public static final Rectangle.Companion Companion = new Rectangle.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final Rectangle ofSize(int width, int height) {
return new Rectangle(width, height);
}
@NotNull
public final Rectangle ofRectangle(@NotNull Rectangle rectangle) {
Intrinsics.checkParameterIsNotNull(rectangle, "rectangle");
return new Rectangle(rectangle.getWidth(), rectangle.getHeight());
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
可以发现,Kotlin 中的 companion object 其实对应到 Java 中也就只是 Rectangle 的一个静态内部类实例而已。
JVM 静态成员(@JvmStatic)
我们把上面 Kotlin 的 main 方法中的代码用 java 重写一遍:
int width = 4;
int height = 5;
Rectangle rectangle1 = new Rectangle(width,height);
Rectangle rectangle2 = Rectangle.Companion.ofSize(width,height);
Rectangle rectangle3 = Rectangle.Companion.ofRectangle(rectangle2);
发现 ofSize 和 ofRectangle 方法并不是通过 Rectangle 类直接调用的,结合上述反编译后的 java 代码,应该不难理解,因为 Kotlin 中 Rectangle 的伴生对象本质上就是这个 Rectangle.Companion 实例,ofSize 和 ofRectangle 都是 Rectangle.Companion 的方法,所以,用 Rectangle.Companion 对象调用它自己的方法这完全没有毛病,可是,难道就不能在 Java 中也像 Kotlin 那样,直接通过 类名.xxx() 的方法来调用伴生对象方法吗?答案肯定是有的啦,Kotlin 提供了 @JvmStatic 和 @JvmField,可以让伴生对象中的方法和属性在 java 中通过类名直接调用:
class Rectangle(val width: Int, val height: Int) {
companion object {
@JvmStatic
fun ofSize(width: Int, height: Int): Rectangle {
return Rectangle(width, height)
}
@JvmStatic
fun ofRectangle(rectangle: Rectangle): Rectangle {
return Rectangle(rectangle.width, rectangle.height)
}
@JvmField
val Tag = "Rectangle"
}
}
这次 java 代码也可以使用 Rectangle 类名来调用 ofSize 和 ofRectangle 方法了:
int width = 4;
int height = 5;
Rectangle rectangle1 = new Rectangle(width, height);
Rectangle rectangle2 = Rectangle.ofSize(width, height);
Rectangle rectangle3 = Rectangle.ofRectangle(rectangle2);
System.out.println(Rectangle.Tag);
再来反编译一次,看其究竟是什么原理,原来就只是在 Rectangle 中增加了对应的 static 属性和方法而已:
public final class Rectangle {
public static final Rectangle.Companion Companion = new Rectangle.Companion((DefaultConstructorMarker)null);
@JvmField
@NotNull
public static final String Tag = "Rectangle";
@JvmStatic
@NotNull
public static final Rectangle ofSize(int width, int height) {
return Companion.ofSize(width, height);
}
@JvmStatic
@NotNull
public static final Rectangle ofRectangle(@NotNull Rectangle rectangle) {
return Companion.ofRectangle(rectangle);
}
public static final class Companion {
@JvmStatic
@NotNull
public final Rectangle ofSize(int width, int height) {
...
}
@JvmStatic
@NotNull
public final Rectangle ofRectangle(@NotNull Rectangle rectangle) {
...
}
}
}
猜你喜欢
- 2024-09-29 直击灵魂一问:协程到底是怎么切换线程的?
- 2024-09-29 八月冲刺别毁在传统一问一答模式,这份面试准备助你事半功倍
- 2024-09-29 Kotlin遇见数据结构丨说说顺序存储的二叉树如何创建遍历
- 2024-09-29 Kotlin实战—使用Room封装本地数据层
- 2024-09-29 知了堂|MybatisPlus—kotlin代码生成
- 2024-09-29 竟然有5种微服务框架可以替代Spring Boot
- 2024-09-29 ViewBinding 与 Kotlin 委托双剑合璧
- 2024-09-29 Kotlin编写一个GIFDialog 在线音视频解析三
- 2024-09-29 Kotlin+SpringBoot+Redis+Lua实现限流访问控制详解
- 2024-09-29 北上广程序员回重庆继续代码 kotlin音视频解析六 收藏
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)