kotlin 之单例类详解

news2025/1/17 3:13:15

object

单例对象的声明:

object  Model{
    var temp = "1"
    val temp2 = "2"
    const val temp3 = "3"
}

抛出疑问:使用object修饰的类,是哪种类型的单例模式

这里我们先回顾一下java六种单例模式

1. 饿汉式
public class HungryMan {

    private HungryMan(){}

    private static HungryMan hungryMan = new HungryMan();

    public static HungryMan getInstance(){
        return hungryMan;
    }
}

优点:简单方便,线程安全

缺点:无论是否用到,都会进行实例化,而且在类加载时就会实例化

2. 懒汉式
public class LazyMan {

    private static LazyMan lazyMan = null;

    private LazyMan() {
    }

    public static LazyMan getInstatce() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

优点:只有在使用时才会生成对象,能够减少内存开销

缺点:线程不安全,只能在单线程中使用,多个线程访问时,会产生多个对象,

3.懒汉式同步锁
public class LazyMan {

    private static volatile LazyMan lazyMan = null;

    private LazyMan() {
    }

    public static LazyMan getInstatce() {
        synchronized (LazyMan.class){
            if (lazyMan == null) {
                lazyMan = new LazyMan();
            }
        }
        return lazyMan;
    }
}

优点:支持多线程

缺点:每次都会有一个加锁以及释放锁的操作,效率低,可以通过反射破坏单例模式。

4.DCL双检测锁
public class LazyMan {

    private static volatile LazyMan lazyMan = null;

    private LazyMan() {
    }

    public static LazyMan getInstatce() {
        if(lazyMan == null){
            synchronized (LazyMan.class){
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}

这里引入一下解释一下DCL双检测锁机制:

DCL双检测锁机制: 用DCL双检测锁机制为什么要用valoatile修饰,因为lazyMan=new LazyMan(), 并非是一个原子操作。事实上在JVM中大概做了3件事。

1.给lazyMan分配内存,

2.调用构造器来初始化成员变量

3.将lazyMan对象指向分配的内存空间。 但是JVM的即时编译器中存在指令重排序的优化,也就是说上面的第二步,第三步顺序是不 确定的一旦2,3,顺序乱了,这个是有一个线程调用了方法,结果虽然是非null,但是未初 始化,所以直接报错。

优点:效率高,线程安全

缺点:代码复杂,可以通过反射破坏单例

5.静态内部类
public class Singleton {
 
    private Singleton() {}
 
    private static class SingletonInstance {//私有静态内部类
        private static final Singleton INSTANCE = new Singleton();
    }
 
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

优点:类的静态属性只有在第一次加载类的时候初始化,所以线程安全

缺点:代码变得复杂,apk文件增大

6. 枚举单例
public enum SingleTon {

    SINGLE_TON;

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}

优点:线程安全,不用担心反射破话单例模式

缺点:枚举类占用内存多

解析:object 单例类是什么类型的单例

这里我们直接将kotlin代码转为Java 代码进行查看。

kotlin代码如下

转为Java之后

我们可以看到,该Model类转为Java代码之后,它是一个饿汉式单例。所以使用object的类采用的是饿汉式单例。

companion object伴生对象出现的单例是哪种类型的单例

kotlin代码如下

class  Model{
    companion object{
        val text = ApiWrapper("11")
    }
}

class ApiWrapper (val api : String){
     fun s() {
      
    }
}

java代码如下

public final class Model {
   @NotNull
   private static final ApiWrapper text = new ApiWrapper("11");
   @NotNull
   public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
      @NotNull
      public final ApiWrapper getText() {
         return Model.text;
      }

      private Companion() {
      }
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

可以看的出来,如果直接对text赋值,那么就相当于是一个饿汉式加载

但是如果我们对text进行by lazy延迟赋值,那么会是什么样子呢。

public final class Model {
   @NotNull
   private static final Lazy text$delegate;
   @NotNull
   public static final Model.Companion Companion = new Model.Companion((DefaultConstructorMarker)null);

   static {
      text$delegate = LazyKt.lazy((Function0)null.INSTANCE);
   }

   public static final class Companion {
      @NotNull
      public final ApiWrapper getText() {
         Lazy var1 = Model.text$delegate;
         Model.Companion var2 = Model.Companion;
         Object var3 = null;
         return (ApiWrapper)var1.getValue();
      }

      private Companion() {
      }

      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

可以看出,此时变成了懒汉式同步单例

至于为什么是同步单例,这里需要大家去看一下LazyKt.lazy()方法

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

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

相关文章

String、StringBuffer和StringBuilder类的区别

在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String 类是不可变类,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。 Java 提供了两个可变字符串类 Stri…

EFLFK——ELK日志分析系统+kafka+filebeat架构(3)

ELFK——ELK结合filebeat日志分析系统(2)_Evens7xxX的博客-CSDN博客 紧接上期,在ELFK的基础上,添加kafka做数据缓冲 附kafka消息队列 nginx服务器配置filebeat收集日志:192.168.116.40,修改配置将采集到的…

SoC-ZCU106求解非线性方程(一):环境安装

一、大家好久不见,本次给大家带来的是SoC求解非线性方程问题。计划发布三篇文章,这是第一篇----环境安装。 主要的解决的问题是:PL侧给PS传输数据,然后PS将数据作为已知量求解非线性方程,为了简化问题复杂度&#xff…

中睿天下实力入选2022信创产业独角兽TOP100

近日,中国科学院主管的权威媒体《互联网周刊》、德本咨询、eNet研究院联合发布了“2022信创产业独角兽100强”榜单。中睿天下凭借在网络安全攻击溯源领域的深耕、硬的技术能力和突出的产品创新力,实力入选榜单,在上榜的安全企业中&#xff0c…

Docker(四)—— 部署Nginx、Tomcat

一、部署Nginx 将Nginx后台挂载后,用curl命令访问,进行本机自测: 二、部署Tomcat 出现404页面的原因:为了缩小镜像的大小,官方下载的Tomcat镜像是精简版的,只提供了必要、核心的内容。我们进入容器内部的/w…

You辉编程_kafka

一、什么是kafka? 是分布式(项目部署于多个服务器)的基于发布/订阅模式的消息队列,主要用于处理活跃的数据,如:登录、浏览、点击、分享等用户行为产生的数据,说白了就是一个消息系统(消息队列)。 进一步…

java项目-第132期ssm学生会管理系统-ssm+shiro+activity社团毕业设计

java项目-第132期ssm学生会管理系统-ssmshiroactivity社团毕业设计 【源码请到资源专栏下载】 今天分享的项目是《学生会管理系统》 该项目分为不同的角色,其中包含超级管理员、生活文体部部长、行政秘书部部长、 外联部部长、策划部部长、学生会干事等角色&#xf…

[附源码]java毕业设计基于的网上饮品店

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

FITC标记葡聚糖(40kDa),FITC Dextran-40,CAS号:60842-46-8

中文名称:FITC标记葡聚糖(40kDa) 英文名称:FITC Dextran-40 CAS号:60842-46-8 产品规格:50mg|250mg|1g 本制品是对平均分子量约40kDa葡聚糖进行标记的荧光素衍生物,即异硫氰酸荧光素葡聚糖40(fluoresce…

QT编译Opencv库过程中出现的问题总结

一、人脸识别模块编译出错 出错原因:没有加入opencv_contrib OpenCV 4.4开始需要提供opencv_contrib 如果不需要人脸识别模块可以进行下列操作 [ 77%] Linking CXX executable ..\..\bin\opencv_test_dnn.exe jom: E:\1WT\18.OCR\opencv\build-sources-Desktop_…

计算机网络 3 - 传输层

第3章 传输层(Transport Layer)3.1 传输层服务与协议3.2 复用 分用无连接的分用、复用(UDP)面向连接的分用、复用(TCP)持续/非持续HTTP连接 与 常见端口3.3 无连接传输: UDP3.4 可靠数据传输原理(rdt)rdt 1.0:经完全可靠信道的可靠数据传输rdt 2.0:发现并…

了解操作符的那些事(二)

小叮当的任意门sizeof 和 数组关系操作符逻辑操作符条件操作符逗号表达式下标引用,函数调用和结果成员下标引用函数调用访问一个结构的成员表达式求值隐式类型转换算术转换操作符的属性前言:~ 对一个数的二进制按位取反 *间接访问操作符(解引用操作符&am…

linux笔记(3):东山哪吒STU开发板(全志D-1H)开箱初体验helloworld

文章目录1.开发板上电观察串口1.1 从nand flash启动1.2 从SD卡启动2.上传文件到开发板2.1 使用FileZilla软件连接开发板2.2 使用ADB软件双11下单后,经过多日的等待,终于在昨天下午收到了开发板。在等待的过程中,看了一下文档和B站东山老师的视…

Java_封装

目录 1.访问修饰限定符 2.封装扩展之包 导入包中的类 3.自定义包 4.包的访问权限控制举例 5.常见的包 6.通过构造方法进行初始化 面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来…

RPC初识

一、为什么要学习RPC 要回答这个问题,那就必须先了解下 RPC 的使用场景。 只要涉及到网络通信,我们就可能用到RPC 大型分布式系统中:消息队列、分布式缓存、分布式数据库、统一配置中心等,应用程序与这些依赖的中间件都可以通过 …

【Java】SpringCloud基础知识点

SpringCloud什么是SpringCloud有哪些组件EurekaRibbonHystrixZuulConfigFeign什么是SpringCloud SpringCloud是一套分布式微服务的解决方案,Spring Cloud 的各个项目基于 Spring Boot,将 Netflix 的多个框架进行封装,并且通过自动配置的方式…

数据的标准化处理——基于python

数据的标准化处理——基于R归一化(normalization)python实现标准化python实现之前写过用R来进行标准化: 数据的标准化处理——基于R归一化(normalization) 将数据缩放到[0,1]的(min—max Normalization&am…

电脑软件:推荐八款图片处理工具,值得收藏

目录 1、Inpaint 图片去水印神器 2、XnView 图片批量管理工具 3、TinyPNG图片压缩网站 4、IrfanView 5、GIMP 开源图片编辑器 6、Paint.NET 好用的图片编辑软件 7、Optimizilla 图片压缩工具 8、iLoveIMG 在线图片编辑工具 日常办公当中,图片处理是经常要用…

.ttf 字体剔除

想在 游戏/应用 中使用字体,让你的应用提升一个逼格;但是发现一个 .ttf 少则 几兆, 大则 十几兆,这时候可以通过 fontTools,来剔除不需要的畸形字体,保留常用字体; 1. 安装 python 环境 自行安装&#xff…

【JavaSE】类和对象 【this引用和构造方法】(二)

目录 1、this引用 1.1、this的三种用法 1.1.1、this.属性名 1.1.2、this.方法名 1.1.3、this ( ) 访问构造方法 详细讲解 1、this引用 1.1、为什么要有this引用 问题1:形参名不小心与成员变量名形同会发生什么问题? 问题2: 1.2、什…