User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Kotlin   ›   Kotlin Notes   ›   正文
Kotlin Notes

Kotlin-类型进阶—单例(二十二)

2021-01-26 00:09:59
1107  0 2
参考目录 隐藏
1) 单例
2) @JvmStatic 和 @JvmField
3) 伴生对象
4) 调用
5) 伴生对象的作用
6) 与 Java 代码共存
7) @JvmField 和 @JvmStatic 的使用(伴生对象)
8) const 关键字
9) 伴生对象的扩展
10) 扩展方法
11) 扩展属性
12) 总结:

阅读完需:约 8 分钟

单例

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

关键点:

  1. 一个类只有一个实例 , 这是最基本的
  2. 它必须自行创建这个实例
  3. 它必须自行向整个系统提供这个实例

两种实现方式:

  1. 懒汉模式 : 需要用的时候,才会创建对象
  2. 饿汉式:加载类的时候,就创建了对象

只需要类前面添加object关键字即可,object定义类等价于java的恶汉式的单例模式

object Singleton {
    var x: Int = 2 
    fun y(){ }

    init {
        //object不能定义构造函数,但可以定义init块
    }
}

调用:

fun main() {
    Singleton.x
    Singleton.y()
}

object不能定义构造函数,但可以定义init块


@JvmStatic 和 @JvmField

单例(object):

object Singleton {
    @JvmField var x: Int = 2 //生成java的静态成员 不会生成getter和setter方法
    @JvmStatic fun y(){ } //生成java的静态方法
}

普通kotlin类(非单例)中使用使用JvmField和JvmStatic:

class Foo {
    //普通类中使用JvmField和JvmStatic
    companion object {
        @JvmField var x: Int = 2
        @JvmStatic fun y(){  }
    }
}

注意,加的注解@JvmField和@JvmStatic只针对java平台的可用,其他平台并不可行。

单例的object类仍可以继承类:

object Singleton: Runnable{
    override fun run() {

    }
}


伴生对象

因为 Kotlin 没有 static 这个概念,尝试着在有 static 概念的 Java 中调用 Kotlin 的 companion object 中的方法或者访问当中的公开属性,是无法做不到的(除非你用 @JvmStatic 进行注释来生成真正的静态方法和变量)。

companion object 并不是所谓的静态写法(很关键)

可以把伴生对象看成是一个普通Java类的单例对象,因为它最终也是按照普通类对象进行编译的,只不过默认给你生成了一个唯一的实例。


在类中定义的对象(object)声明,可使用 companion 修饰,这样此对象(object)就是伴生对象了。如下例子:

class NumberTest {
    companion object Obj {  
        var flag = false

        fun plus(num1: Int, num2: Int): Int {
            return num1 + num2
        }
    }
}

在本例中,类 NumberTest 中就声明了一个伴生对象,包含属性 flag 和 方法 plus()。但是一个类(class)中最多只能定义一个伴生对象。

调用

使用 companion 关键字修改的对象之后,伴生对象就相当于是外部类的对象,我们可以使用类直接调用,如下:

fun main(args: Array<String>) {

    println(NumberTest.plus(1, 2))  // 3
    println(NumberTest.flag)  // false

}

从上面的代码可以看出调用的时候与伴生对象的名称没有多大关系,所以名称 Obj 可以省略不写。

伴生对象的作用

通过上面的 NumberTest.plus(1, 2) 和 NumberTest.flag 代码不难看出来,类似于 Java 中使用类访问静态成员的语法。因为 Kotlin 取消了 static 关键字,所以 Kotlin 引入伴生对象来弥补没有静态成员的不足。可见,伴生对象的主要作用就是为其所在的外部类模拟静态成员。

与 Java 代码共存

知道了伴生对象的特点之后,那么我们如何与 Java 代码共存呢?

public class NumberJavaTest {

    public static void main(String[] args) {
        System.out.println(NumberTest.Obj.plus(2, 3)); // 5
        // System.out.println(NumberTest.Companion.plus(2, 3));
        NumberTest.Obj.setFlag(true);
        // NumberTest.Companion.setFlag(true);
        System.out.println(NumberTest.Obj.getFlag()); // true
        // System.out.println(NumberTest.Companion.getFlag());
    }

}
  • 如果声明伴生对象有名称,则使用:
类名.伴生对象名.方法名()
类名.半生对象名.属性的setter,getter方法

例:NumberTest.Obj.plus(2, 3)
  • 如果声明伴生对象无名称,则采用 Companion 关键字调用:
类名.Companion.方法名()
类名.Companion.属性的setter,getter方法

例:NumberTest.Companion.getFlag()

@JvmField 和 @JvmStatic 的使用(伴生对象)

我们知道了可以在 Java 代码中调用 Kotlin 中伴生对象的成员,类似于 Java 类中的静态成员。但是看上去和 Java 中的还是略有区别,因为类名和方法名/属性setter,getter方法名之间多了个伴生对象的名称或者 Companion 关键字。如何使其在调用的时候与 Java 中的调用看上去一样呢?

Kotlin 为我们提供了 @JvmField 和 @JvmStatic 两个注解。@JvmField 使用在属性上,@JvmStatic 使用在方法上。如:

class NumberTest {
    companion object {
        @JvmField
        var flag = false

        @JvmStatic
        fun plus(num1: Int, num2: Int): Int {
            return num1 + num2
        }
    }
}

这样我们在 Java 代码中调用的时候就和 Java 类调用静态成员的形式一致了,Kotlin 代码调用方式不变:

 public static void main(String[] args) {
        System.out.println(NumberTest.plus(2, 3));
        NumberTest.flag = true;
        System.out.println(NumberTest.flag);
}

const 关键字

在伴生对象中,我们可能需要声明一个常量,目的是等同于 Java 中的静态常量。有两种方式,一种是上面所提到的使用 @JvmField 注解,另一种则是使用 const 关键字修饰。这两种声明方式都等同于 Java 中 static final 所修饰的变量。如下代码:

companion object {
      const val m = 2

      @JvmField
      val n = 3
}

// java 代码中调用:
System.out.println(NumberTest.m);
System.out.println(NumberTest.n);

如果不使用 const 修饰的常量,我们需要引用伴生对象来调用,而且必须调用 getter 方法。

companion object {
      const val k = 2
}

// java 代码中调用:
System.out.println(NumberTest.Companion.getK());

而以上 const 关键字使用的影响只是在 Java 中调用方式不同,在 Kotlin 中并无影响。

伴生对象的扩展

如果了解 Kotlin 的话,应该知道在 Kotlin 中,对象时可以被扩展的。在 Kotlin 中,如果类中包含伴生对象,则 Kotlin 允许伴生对象扩展方法和属性。也就是为伴生对象所在的外部类扩展静态成员,访问方式一致。

接着上面的列子,为上面的 NumberTest 类扩展一个 minus 方法:

扩展方法

fun NumberTest.Companion.minus(str: String): Int {
    if (str != null && str.isNotEmpty()) {
        return try {
            str.toInt()
        } catch (e: Exception) {
            0
        }
    }
    return 0
}

通过例子我们看出,我们可以通过类名去扩展方法,如果伴生对象有名称的话,使用 类名.伴生对象名.方法名()来扩展,否则使用 类名.Companion.方法名()来扩展即可。

扩展属性

var NumberTest.Companion.number
    get() = 3
    set(value) {
        // set 方法并没有 field 可以用来存储 value
        this.plus(value, 2)
    }

val NumberTest.Companion.str
    get() = "这是一个扩展属性"

同样,我们也可以扩展属性,但是扩展属性有以下几个特点:

  • 扩展属性不能有初始值,没有 field 来存储属性值;
  • 扩展属性因为没字段来存储值,所以为计算属性;
  • 扩展 var 属性必须提供 setter 和 getter 方法,扩展 val 属性必须提供 getter 属性。

总结:

  • 每个类可以最多有一个半生对象;
  • 伴生对象的成员类似于 Java 的静态成员;
  • 使用 const 关键字修饰常量,类似于 Java 中的 static final修饰。
  • 可以使用 @JvmField 和 @JvmStatic 类似于 Java 中调用静态属性和静态方法;
  • 伴生对象可以扩展属性和扩展方法。

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

2 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594442浏览

随机文章
MyBatisPlus—分页查询以及自定义sql分页
5年前
MyBatis笔记3.1—使用注解开发
5年前
Java—并发编程(六)JUC锁 – (8) CountDownLatch
4年前
Spring—注解驱动开发Spring Ioc容器中注册Bean的7种方式
5年前
SpringBoot—中实现定时任务的两种方式 + 异步任务
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594442 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付