Mengapa enum singleton malas?
Saya melihat jawaban seperti ini , mencoba mengklarifikasi melalui komentar , dan tidak puas dengan contoh di sini .
Mungkin sudah waktunya untuk pertanyaan khusus ini ...
Mengapa implementasi enum singleton disebut lazy ?
public enum EnumLazySingleton {
INSTANCE;
EnumLazySingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
Apa bedanya dengan implementasi yang bersemangat ?
public class BasicEagerSingleton {
private static final BasicEagerSingleton instance = new BasicEagerSingleton();
public static BasicEagerSingleton getInstance() {
return instance;
}
private BasicEagerSingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
Keduanya akan memulai instance tanpa mengakses INSTANCE/getInstance()- mis touchClass(). Panggilan .
public class TestSingleton {
public static void main(String... args) {
System.out.println("sleeping for 5 sec...");
System.out.println("touching " + BasicEagerSingleton.class.getSimpleName());
BasicEagerSingleton.touchClass();
System.out.println("touching " + EnumLazySingleton.class.getSimpleName());
EnumLazySingleton.touchClass();
}
}
Keluaran:
sleeping for 5 sec...
touching BasicEagerSingleton
constructing: BasicEagerSingleton@7bfcd12c
touching EnumLazySingleton
constructing: INSTANCE
Sekarang, kita bisa mengatakan keduanya malas . Lalu apa yang sangat ingin ?
Jelas bagaimana (misalnya) cara "penguncian yang diperiksa dua kali" sebenarnya malas (dan berantakan, dan lambat). Tetapi jika enum adalah malas, maka setiap singleton menjadi malas karena pemuatan kelas yang tak terhindarkan - pada kenyataannya, semuanya malas. Pada titik manakah perbedaan ini akan berhenti masuk akal?
Jawaban
Dua jawaban terkait pertama (oleh Peter Lawrey dan Joachim Sauer ) keduanya setuju bahwa enum tidak diinisialisasi dengan malas. Jawaban di tautan ketiga salah tentang arti inisialisasi malas.
Rekomendasi untuk menggunakan enum sebagai lajang berasal dari Java Efektif Josh Bloch. Khususnya, bab tentang enum singletons tidak menyebutkan kemalasan. Ada bab selanjutnya yang didedikasikan untuk inisialisasi malas, yang juga tidak menyebutkan enum. Bab ini berisi dua sorotan.
- Jika Anda perlu menggunakan inisialisasi lambat untuk performa di kolom statis, gunakan idiom kelas lazy initialization holder.
- Jika Anda perlu menggunakan inisialisasi lambat untuk performa di kolom instance, gunakan idiom pemeriksaan ulang.
Tidak diragukan lagi, enum akan menjadi idiom lain dalam daftar ini jika mereka diinisialisasi dengan malas. Sebenarnya tidak, meskipun kebingungan tentang arti inisialisasi malas menghasilkan beberapa jawaban yang salah, seperti yang ditunjukkan OP.
Bolehkah saya bertaruh yang berikut:
Anda mencoba mengidentifikasi 2 "proses" atau ... "things"(mari kita buat ini mudah dipahami - karena jika saya mulai mengatakan "Blok Kode", kedengarannya lebih sulit) ...
- Pada titik tertentu class-loader akan berjalan, dan Anda ingin tahu apa yang
"things"akan dieksekusi ketika class-loader memuat sebuah kelas. - Pada titik lain, memanggil metode pada kelas akan menyebabkan metode lain
"thing"dijalankan / dijalankan, dan Anda ingin tahu mana, tepatnya, (yang mana"processes") akan dimulai ..
Fakta-fakta berikut ini relevan:
- Penginisialisasi statis dijalankan ketika class-loader memuat kelas. Pemuat kelas tidak akan memuat kelas sampai kode yang berjalan memenuhi kebutuhan untuk memuatnya (karena metode atau bidang telah dipanggil) seperti:
touchClass()- Jika sebuah instance tunggal dari SALAH SATU kelas, ATAU tipe yang disebutkan memiliki
fieldyang diinisialisasi distaticbagian kelas itu akan dimuat segera setelah Anda 'menyentuh' kelas - karena Class-Loader menjalankan semuastatic initializationsuntuk kelas atau enum saat memuat.- Pemuatan lambat, kemungkinan besar, (Dan ini adalah "interpretasi" saya tentang apa yang Anda tanyakan) akan terjadi ketika pemanggilan metode meminta kelas untuk membuat instance tunggal - yang bisa terjadi cukup lama setelah "pemuatan" dari
classatauenum.
Kelas seperti berikut:
public class LazySingleton
{
// At time of class-loading, this singleton is set to 'null'
private static singleton = null;
// This is a method that will not be invoked until it is called by
// some other code-block (some other "thing")... When "touchClass()"
// is called, the singleton instance is not created.
public static LazySingleton retrieveSingleton()
{
if (singleton == null) singleton = new LazySingleton();
return singleton;
}
// DOES NOTHING... The Singleton is *not* loaded, even though the
// Class Loader has already loaded this Java ".class" file
// into memory.
public static void touchClass() { }
private LazySingleton()
{ System.out.println("constructing: LazySingleton"); }
}
Di sini, di sisi lain:
public enum EagerEnum
{
// The class loader will run this constructor as soon as this 'enum'
// is loaded from a '.class' file (in JAR or on disk) into memory
MyEnumConstant();
private EagerEnum()
{ System.out.println("Eager Enum Constructed"); }
// This will cause the Class Loader to Load this enum from the
// Java ".class" File immediately, and the "MyEnumConstant" will
// also have to be loaded - meaning the constructor will be called.
public static void touchEnum() { }
}
Jadi kode berikut akan menghasilkan keluaran
LazySingleton.touchClass(); // Prints nothing
EagerEnum.touchClass(); // Prints "Eager Enum Constructed"
LazySingleton.getSingletonInstance(); // Prints "constructing: LazySingleton