深入讨论kotlin中的object初始化时机,到底是饿汉还是懒汉?

很多博客说kotlin的object对象声明是饿汉式的单例
https://kaixue.io/kotlin-basic-2/

但官方说是延迟初始化

于是我自己来尝试一下,测试文件为Test.kt,包名是cn.janking.myandroid.hub

1、简单测试

直接运行程序,看输出
发现在第一行执行完之后才执行Test的初始化代码块

但是有的同学就要问题:这也不能确定没有加载Test 的类是吧?

所以来看第二步

2、看类加载器

加两个断点分别放在Test类使用的前后,看看Test类是不是延迟加载的
在调用Test类之前已经加载了15个类

在调用Test类之后已经加载了16个类

多的那个类正好就是Test

也就是说Test仍然是在使用的时候才初始化,那这也是饿汉式?

3、思考

其实这就是饿汉式和懒汉的的定义区别了,它是指在获取单例对象的时候才初始化还是在获取单例对象之前就初始化,而饿汉式在获取单例对象的时候才初始化。

java中,如果要定义一个Test的单例对象,是这样的

根据类加载机制,在没有调用Test的时候这个instance是不会初始化的,并不会提前占用内存,那为什么说它不是懒加载呢?

那我们要想想如果多加一个字段呢

在某些地方如果要使用Test.TAG是不是就会把这个类给加载出来?
是不是这个instance就提前加载到内存里了?

所以饿汉和懒汉的区别不是类加载的时候有没有初始化instance,而是没有调用getInstance的时候有没有初始化instance

在来看kotlin,似乎不太一样,因为这个object整个就是instance,会不会有上面说到的情况有个TAG这种需要访问但是又不想初始化实例的情况呢?

在object(官方称之为对象声明)这种情况下,如果在内部定义一个属性,那它就是属于这个单例的属性,如果要访问那就说明你肯定需要访问这个单例,会不会有类似于那种独立于单例的属性呢?

可能你想到了companion,但是object中禁止用companion

貌似没了......

来看一下kotlin反编译的java代码

好家伙,array这个属性直接给我弄成static了,那这个INSTANCE有啥用,貌似只是个门面......

4、例外

经过评论区提醒,如果给Test类添加一个JvmStatic的注解是可以实现一个public static final的类似于TAG的变量的

5、总结一下

1、饿汉和懒汉的区别只是在于 使用了单例类 但是不想初始化instance的情况,在你没使用单例类的情况(类加载的几种时机)下都是一样的不会初始化instance
2、kotlin中的object(对象声明)用的是相当于java中的饿汉式,但是只有在添加了
JvmStatic的情况下才会出现1中说的那种情况,即没有改注解时你无法去添加一个静态函数或静态变量 导致 出现 访问了这个类但是没访问这个单例情况。也就是说没有JvmStatic变量就是懒汉,有JvmStatic可能是饿汉。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页