kotlin 之单例类详解

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()方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin中创建PopupWindow的单例可以通过以下步骤实现: 1. 创建一个名为PopupWindowSingleton的Kotlin对象,该对象将作为PopupWindow的单例。 2. 在PopupWindowSingleton对象中声明一个私有的PopupWindow变量,用于保存单例的实例。 3. 在PopupWindowSingleton对象中声明一个公共的getInstance()方法,用于获取PopupWindow的单例实例。 4. 在getInstance()方法中,检查PopupWindow实例是否已经被创建。如果已经创建,则直接返回该实例;如果尚未创建,则创建一个新的PopupWindow实例并保存到变量中。 5. 在getInstance()方法中,设置PopupWindow的属性,例如宽度、高度、背景等。 6. 在getInstance()方法中,返回PopupWindow的单例实例。 以下是一个示例代码: ```kotlin class PopupWindowSingleton private constructor() { private var popupWindow: PopupWindow? = null companion object { private var instance: PopupWindowSingleton? = null fun getInstance(): PopupWindowSingleton { if (instance == null) { instance = PopupWindowSingleton() instance?.popupWindow = PopupWindow() // 设置PopupWindow的属性 instance?.popupWindow?.width = WindowManager.LayoutParams.WRAP_CONTENT instance?.popupWindow?.height = WindowManager.LayoutParams.WRAP_CONTENT instance?.popupWindow?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) } return instance!! } } fun showPopupWindow(view: View) { // 显示PopupWindow instance?.popupWindow?.showAsDropDown(view) } } ``` 使用时,可以通过调用PopupWindowSingleton.getInstance()方法获取PopupWindow的单例实例,并调用showPopupWindow()方法显示PopupWindow。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值