Kotlin教程笔记(14) - 伴生对象与静态成员

简介: Kotlin教程笔记(14) - 伴生对象与静态成员

本系列学习教程笔记属于详细讲解Kotlin语法的教程,需要快速学习Kotlin语法的小伙伴可以查看“简洁” 系列的教程

快速入门请阅读如下简洁教程:
Kotlin学习教程(一)
Kotlin学习教程(二)
Kotlin学习教程(三)
Kotlin学习教程(四)
Kotlin学习教程(五)
Kotlin学习教程(六)
Kotlin学习教程(七)
Kotlin学习教程(八)
Kotlin学习教程(九)
Kotlin学习教程(十)

​ Kotlin教程笔记(14) - 伴生对象与静态成员

imgKotlin - 伴生对象与静态成员

#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);

发现 ofSizeofRectangle 方法并不是通过 Rectangle 类直接调用的,结合上述反编译后的 java 代码,应该不难理解,因为 Kotlin 中 Rectangle 的伴生对象本质上就是这个 Rectangle.Companion 实例,ofSizeofRectangle 都是 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) {
   
          ...
      }
   }
}
目录
相关文章
|
5天前
|
人工智能 自动驾驶 大数据
预告 | 阿里云邀您参加2024中国生成式AI大会上海站,马上报名
大会以“智能跃进 创造无限”为主题,设置主会场峰会、分会场研讨会及展览区,聚焦大模型、AI Infra等热点议题。阿里云智算集群产品解决方案负责人丛培岩将出席并发表《高性能智算集群设计思考与实践》主题演讲。观众报名现已开放。
|
21天前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
|
25天前
|
存储 人工智能 调度
阿里云吴结生:高性能计算持续创新,响应数据+AI时代的多元化负载需求
在数字化转型的大潮中,每家公司都在积极探索如何利用数据驱动业务增长,而AI技术的快速发展更是加速了这一进程。
|
16天前
|
并行计算 前端开发 物联网
全网首发!真·从0到1!万字长文带你入门Qwen2.5-Coder——介绍、体验、本地部署及简单微调
2024年11月12日,阿里云通义大模型团队正式开源通义千问代码模型全系列,包括6款Qwen2.5-Coder模型,每个规模包含Base和Instruct两个版本。其中32B尺寸的旗舰代码模型在多项基准评测中取得开源最佳成绩,成为全球最强开源代码模型,多项关键能力超越GPT-4o。Qwen2.5-Coder具备强大、多样和实用等优点,通过持续训练,结合源代码、文本代码混合数据及合成数据,显著提升了代码生成、推理和修复等核心任务的性能。此外,该模型还支持多种编程语言,并在人类偏好对齐方面表现出色。本文为周周的奇妙编程原创,阿里云社区首发,未经同意不得转载。
11596 12
|
10天前
|
人工智能 自然语言处理 前端开发
100个降噪蓝牙耳机免费领,用通义灵码从 0 开始打造一个完整APP
打开手机,录制下你完成的代码效果,发布到你的社交媒体,前 100 个@玺哥超Carry、@通义灵码的粉丝,可以免费获得一个降噪蓝牙耳机。
4092 14
|
17天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
6849 10
|
29天前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
15天前
|
人工智能 自然语言处理 前端开发
什么?!通义千问也可以在线开发应用了?!
阿里巴巴推出的通义千问,是一个超大规模语言模型,旨在高效处理信息和生成创意内容。它不仅能在创意文案、办公助理、学习助手等领域提供丰富交互体验,还支持定制化解决方案。近日,通义千问推出代码模式,基于Qwen2.5-Coder模型,用户即使不懂编程也能用自然语言生成应用,如个人简历、2048小游戏等。该模式通过预置模板和灵活的自定义选项,极大简化了应用开发过程,助力用户快速实现创意。
|
3天前
|
机器学习/深度学习 人工智能 安全
通义千问开源的QwQ模型,一个会思考的AI,百炼邀您第一时间体验
Qwen团队推出新成员QwQ-32B-Preview,专注于增强AI推理能力。通过深入探索和试验,该模型在数学和编程领域展现了卓越的理解力,但仍在学习和完善中。目前,QwQ-32B-Preview已上线阿里云百炼平台,提供免费体验。
|
11天前
|
人工智能 C++ iOS开发
ollama + qwen2.5-coder + VS Code + Continue 实现本地AI 辅助写代码
本文介绍在Apple M4 MacOS环境下搭建Ollama和qwen2.5-coder模型的过程。首先通过官网或Brew安装Ollama,然后下载qwen2.5-coder模型,可通过终端命令`ollama run qwen2.5-coder`启动模型进行测试。最后,在VS Code中安装Continue插件,并配置qwen2.5-coder模型用于代码开发辅助。
757 5