java 为什么这些创建单例的方法与按需定制保持器(IODH)习惯用法不同?

b09cbbtk  于 2023-10-14  发布在  Java
关注(0)|答案(2)|浏览(142)

你好,我试图理解JMM,以及为什么某些操作是这样工作的。
我想理解为什么下面使用静态变量和静态初始化器的方法与按需调用保持器(IODH)习惯用法不同。

选项一:初始化一个静态变量

public class Singleton {
private static Singleton instance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
    return instance;
    }
}

选项2:静态初始化器

public class Singleton {
private static Singleton instance = null;

static {
    instance = new Singleton();
    }

private Singleton() {
   }

public static Singleton getInstance() { return instance;}   
}

为什么我认为这些应该与IODH习语相同:

  • JLS指定静态初始化器在有人触摸实际类之前不会被触摸。所以,这适用于静态变量,对吗?

静态字段的显式初始值设定项作为初始化的一部分执行

  • 所有类都由类加载器按需加载。

我哪里做错了?

ljo96ir5

ljo96ir51#

它们(选项1和2)与IODH不同。IODH的目的是指定当getInstance()方法被调用时,静态字段将被初始化,而不是以任何方式触及类。因此,它使静态引用初始化更显式。作为参考,IODH看起来是这样的:

public class Singleton {
  private Singleton() {}

  private static class Holder {
    private static final Singleton INSTANCE = new Singleton();
  }

  public static Singleton getInstance() {
    return Holder.INSTANCE;
  }
}
u3r8eeie

u3r8eeie2#

在早期初始化的情况下,每当在运行时代码中引用类时,都会加载类定义(来自.class文件),并加载其所有静态成员(包括.静态块)被初始化。例如,如果你在单例类中有一个这样的方法,并且你在客户端代码(Singleton.doSomething)中引用它,你会看到这个类被示例化了,尽管你没有显式地调用getInstance()方法,因为静态成员被初始化了。

public class Singleton {
  private Singleton() {
      System.out.println("Singleton initialized");
  }

  private static Singleton instance = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() {
    return instance;
    }

  public static void doSomething() {
      System.out.println("Singleton doing something");
    }
}

然而,当你对IODH单例做同样的事情时,只有"LazyRegistryIODH doSomething"消息会被打印到控制台,而LazyRegistryIODH的构造函数不会被调用,因为没有静态字段或块要初始化。

public class LazyRegistryIODH {
    private LazyRegistryIODH() {
        System.out.println("LazyRegistryIODH initialized");
    }

    private static class Holder {
        static final LazyRegistryIODH INSTANCE = new LazyRegistryIODH();
    }

    protected static void doSomething() {
        System.out.println("LazyRegistryIODH doSomething");
    }

    public static LazyRegistryIODH getInstance() {
        return Holder.INSTANCE;
    }
}

相关问题