在java中,我们可以使用双重判断锁定&不稳定的:

    public class Singleton {
        private static volatile Singleton instance;

        public static Singleton getInstance(String arg) {
        Singleton localInstance = instance;
        if (localInstance == null) {
            synchronized (Singleton.class) {
                localInstance = instance;
                if (localInstance == null) {
                    instance = localInstance = new Singleton(arg);
                }
            }
        }
        return localInstance;
    }
}

我们怎么能用kotlin写呢?


About object

object A {
    object B {}
    object C {}
    init {
        C.hashCode()
    }
}

I used kotlin decompiler to get that

public final class A {
   public static final A INSTANCE;

   private A() {
      INSTANCE = (A)this;
      A.C.INSTANCE.hashCode();
   }
   static {
      new A();
   }

   public static final class B {
      public static final A.B INSTANCE;
      private B() {
         INSTANCE = (A.B)this;
      }
      static {
         new A.B();
      }
   }

   public static final class C {
      public static final A.C INSTANCE;
      private C() {
         INSTANCE = (A.C)this;
      }
      static {
         new A.C();
      }
   }
}

All of object have constructor invoke in static block. Based on it, we can think that it's not lazy.

С输给正确答案.

    class Singleton {
        companion object {
            val instance: Singleton by lazy(LazyThreadSafetyMode.PUBLICATION) { Singleton() }
        }
    }

反编译:

public static final class Companion {
      // $FF: synthetic field
      private static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Singleton.Companion.class), "instance", "getInstance()Lru/example/project/tech/Singleton;"))};

      @NotNull
      public final Singleton getInstance() {
         Lazy var1 = Singleton.instance$delegate;
         KProperty var3 = $$delegatedProperties[0];
         return (Singleton)var1.getValue();
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }

I hope Kotlin developers will make non reflection implementation in future...

推荐答案

Kotlin有与您的Java代码等效的代码,但更安全.您的double lock check不建议是even for Java.在Java中,您应该使用inner class on the static,这在Initialization-on-demand holder idiom中也有解释.

But that's Java. In Kotlin, simply use an object (and optionally a lazy delegate):

object Singletons {
    val something: OfMyType by lazy() { ... }

    val somethingLazyButLessSo: OtherType = OtherType()
    val moreLazies: FancyType by lazy() { ... }
}

You can then access any member variable:

// Singletons is lazy instantiated now, then something is lazy instantiated after.  
val thing = Singletons.something // This is Doubly Lazy!

// this one is already loaded due to previous line
val eager = Singletons.somethingLazyButLessSo

// and Singletons.moreLazies isn't loaded yet until first access...

Kotlin有意避免人们对Java中的单例的混淆.并避免了这种模式的"错误版本"——其中有很多.相反,它提供了更简单、最安全的单身形式.

考虑到lazy()的使用,如果你有其他成员,每个人都会懒惰.由于它们是在传递给lazy()的lambda中初始化的,所以您可以做一些定制构造函数和每个成员属性的事情.

因此,您可以延迟加载Singletons个对象(on first access of instance),然后延迟加载something个对象(on first access of member),并且在对象构造方面具有完全的灵活性.

See also:

As a side note, look at object registry type libraries for Kotlin that are similar to dependency injection, giving you singletons with injection options:

Kotlin相关问答推荐

Ktor错误:未指定端口或sslPort

Kotlin和JavaFX:绑定行为奇怪

我如何测试一个可组合组件没有显示,但如果它不存在也接受?

Kotlin编译器如何决定是否可以在任何给定点调用Suspend方法?

使用 Kotlin 的 Springboot 中缺少 ResponseEntity 正文属性

当 func 重载时,kotlin 如何确定调用哪个 func?

如何为 Kotlin 中的每个循环设置以避免越界异常

Jetpack compose 可滚动表格

在 Kotlin 中使用 @Parcelize 注释时如何忽略字段

无法从 XML 访问 NavHostFragment

找不到 androidsdk.modules

将 Firebase 数据快照反序列化为 Kotlin 数据类

Kotlin/JS,Gradle 插件:无法加载@webpack-cli/serve命令

ObjectAnimator.ofFloat 不能直接在kotlin中取Int作为参数

重复构建失败To use Coroutine features, you must add `ktx`......

spring.config.location 在 Spring Boot 2.0.0 M6 上不起作用

判断EditText是否为空kotlin android

如何在伴随对象中使用泛型

在 Kotlin 中声明 Byte 会出现编译时错误The integer literal does not conform to the expected type Byte

Kotlin 是否支持部分应用程序?