Singleton via enum sposób jest Lazy inicjalizacji?

Jest to bardzo szeroko rozpowszechniony kod enum singleton:

public enum enumClazz{
   INSTANCE
   enumClazz(){
     //do something
   }
}

I kilka miejsc mówiło, że to leniwa inicjalizacja. Ale jestem zdezorientowany po przeczytaniu rozdziału 7 ' Inside The Java Virtual Machine ' -- the Lifetime of a Type:

Specyfikacja maszyny wirtualnej Java daje implementacje elastyczność w czasie ładowania i łączenia klas i interfejsów, ale ściśle określa Czas inicjalizacji. Wszystkie wdrożenia musi zainicjować każdy klasy lub interfejsu przy pierwszym aktywnym użyciu. Na następujące sześć sytuacji kwalifikuje się jako aktywne zastosowania:

  • tworzona jest nowa instancja klasy (w bajtodach wykonanie nowej instrukcji. Alternatywnie, poprzez niejawne tworzenie, odbicie, klonowanie lub deserializacja.)
  • W przeciwieństwie do innych metod, które nie są używane przez klasy, nie są używane przez klasy, które nie są używane przez klasy.]}
  • użycie lub przypisanie pola statycznego zadeklarowanego przez klasy lub interfejsu, z wyjątkiem pól statycznych, które są ostateczne i zainicjalizowane przez wyrażenie stałej czasowej kompilacji (w bytekodach wykonanie Instrukcja getstatic lub putstatic)
  • wywołanie pewnych refleksyjnych metod w Java API, takich jak metody w klasie Class lub w klasach w java.lang.reflect pakiet
  • inicjalizacja podklasy klasy (Inicjalizacja klasy wymaga uprzedniej inicjalizacji jej klasy nadrzędnej.)
  • Po uruchomieniu Wirtualnej Maszyny Java, Klasa ta jest oznaczana jako klasa początkowa (z metodą main ()

Trzeci punkt z pogrubionym stylem wyjaśnia, że jeśli pole jest static final, inicjalizacja pola następuje w czasie kompilacji. Podobnie, INSTANCE w enumClazz jest w domyśle równe public static final i zgodne z punktem trzecim.

Czy ktoś może mnie poprawić, jeśli moje zrozumienie jest złe?
Author: naXa, 2013-05-27

2 answers

enum pola instancji są , a nie "zainicjalizowane wyrażeniem stałej czasowej kompilacji". Oni nie może być, ponieważ tylko String i typy prymitywne są możliwymi typami dla wyrażenia stałej czasowej kompilacji .

Oznacza to, że klasa zostanie zainicjowana, gdy INSTANCE zostanie po raz pierwszy uzyskana (co jest dokładnie pożądanym efektem).

Wyjątek w pogrubionym tekście powyżej istnieje, ponieważ te stałe (static final pola zainicjalizowane stałą czasu kompilacji wyrażenie) będzie skutecznie inlinowane podczas kompilacji:

class A {
  public static final String FOO = "foo";

  static {
    System.out.println("initializing A");
  }
}

class B {
  public static void main(String[] args) {
    System.out.println(A.FOO);
  }
}

Wykonywanie klasy B w tym przykładzie spowoduje Nie zainicjalizowanie A (i Nie wypisanie "inicjalizacja a"). Jeśli spojrzysz w kod bajtowy wygenerowany dla B zobaczysz literał Łańcuchowy o wartości "foo" i nie ma odniesienia do klasy A.

 25
Author: Joachim Sauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-17 15:33:03

Trzeci punkt z pogrubionym stylem wyjaśnia, że jeśli pole jest "static final", inicjalizacja pola następuje w czasie kompilacji

Nie do końca-dotyczy tylko " statycznych pól, które są ostateczne i zainicjowane wyrażeniem stałej czasu kompilacji":

static final String = "abc"; //compile time constant
static final Object = new Object(); //initialised at runtime

W Twoim przypadku singleton zostanie zainicjowany po załadowaniu klasy enum, tzn. po raz pierwszy enumClazz jest odwołany w Twoim kodzie.

Więc jest skutecznie leniwy, chyba, że masz w kodzie jakieś oświadczenie, które używa enum.

 4
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-13 16:05:19