This is a very wide-spread enum singleton code:
public enum enumClazz{
INSTANCE
enumClazz(){
//do something
}
}
and a bunch of places said it is a lazy initialization. But I am confused after I read Chapter 7 of 'Inside the Java Virtual Machine' -- The Lifetime of a Type:
The Java virtual machine specification gives implementations flexibility in the timing of class and interface loading and linking, but strictly defines the timing of initialization. All implementations must initialize each class or interface on its first active use. The following six situations qualify as active uses:
- A new instance of a class is created (in bytecodes, the execution of a new instruction. Alternatively, via implicit creation, reflection, cloning, or deserialization.)
- The invocation of a static method declared by a class (in bytecodes, the execution of an invokestatic instruction)
- The use or assignment of a static field declared by a class or interface, except for static fields that are final and initialized by a compile-time constant expression (in bytecodes, the execution of a getstatic or putstatic instruction)
- The invocation of certain reflective methods in the Java API, such as methods in class Class or in classes in the java.lang.reflect package
- The initialization of a subclass of a class (Initialization of a class requires prior initialization of its superclass.)
- The designation of a class as the initial class (with the main()< method) when a Java virtual machine starts up
The third point with bold style clarify that if the field is static final
, the initialization of the field is happened at compile-time. Likewise, the INSTANCE
in enumClazz
is implicitly equal to public static final
and comply with the third point.
Can someone correct me if my understanding is wrong?
2 Answers 2
enum
instance fields are not "initialized by a compile-time constant expression". They
can't be, because only String
and primitive types are possible types for a compile-time constant expression.
That means that the class will be initialized when INSTANCE
is first accessed (which is exactly the desired effect).
The exception in the bold text above exists, because those constants (static final
fields initialized with a compile-time constant expression) will effectively be inlined during compilation:
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);
}
}
Executing class B
in this example will not initialize A
(and will not print "initializing A"). And if you look into the bytecode generated for B
you'll see a string literal with the value "foo" and no reference to the class A
.
-
That means that the class will be initialized when
INSTANCE
is first accessed. If enum class hasstatic
method (any - make itvoid
and do nothing), this enum class and all its instances will be initialized immediately when thisstatic void
method is called. (!) So, you don't need to accessINSTANCE
to initialize it - call that extra method. Done. It's confusing how this enum way is lazy. It is as lazy as simple eager singleton implementation with final field - you call itsstatic void
method and finalinstance
field gets initialized (lazy on first access?).uvsmtid– uvsmtid2020年09月23日 17:14:27 +00:00Commented Sep 23, 2020 at 17:14 -
1@uvsmtid: I'm unsure what you're trying to say. Yes, obviously calling a method on an enum class will also force it to be initialized, just like calling any method on a class will ensure that that class is initialized.Joachim Sauer– Joachim Sauer2020年09月23日 21:29:47 +00:00Commented Sep 23, 2020 at 21:29
-
Correct. Now if it is another lazy implementation (e.g. double-checked locking), the singleton instance is not initialized until
getInstance()
is called - I can see how it is lazy. I don't see how enum approach is lazier than the simplest eager singleton implementation: in both cases, an instance is initialized on the first use of any other (static) method of the class.uvsmtid– uvsmtid2020年09月24日 02:32:01 +00:00Commented Sep 24, 2020 at 2:32 -
1No one is arguing that this is somehow "lazier" than the other implementation. It's simply yet another way to implement that pattern where the JVM helps with the nasty reliably-initialize-under-multi-threaded-access-but-only-at-most-once problem. Personally I prefer to use singletons implemented via some DI framework over both this or a double-check pattern, but that's not in the scope of this question. This question was about "how is this lazy if the value is a compile time constant" (to which the answer is: it's not a compile time constant).Joachim Sauer– Joachim Sauer2020年09月24日 06:43:04 +00:00Commented Sep 24, 2020 at 6:43
-
1Well, the title ls "Singleton via enum way is lazy initialized?" and the content says "a bunch of places said it is a lazy initialization". Other Q&As refer to enum way as lazy. So all this does indicate that it is somehow lazier than something eager. NVM, I simply posted direct question.uvsmtid– uvsmtid2020年09月24日 18:12:03 +00:00Commented Sep 24, 2020 at 18:12
The third point with bold style clarify that if the field is 'static final', the initialzation of the field is happened at complie-time
Not exactly - it only applies to "static fields that are final and initialized by a compile-time constant expression":
static final String = "abc"; //compile time constant
static final Object = new Object(); //initialised at runtime
In your case, the singleton will be initialised when the enum class is loaded, i.e. the first time enumClazz
is referenced in your code.
So it is effectively lazy, unless of course you have a statement somewhere else in your code that uses the enum.
-
class Singleton{public static final instance = new Singleton();...} So, for the generic class way, this 'instance' is lazy initialized?vash_ace– vash_ace2013年05月27日 14:44:07 +00:00Commented May 27, 2013 at 14:44
-
Yes it would be lazily initialised the same way.assylias– assylias2013年05月27日 15:06:20 +00:00Commented May 27, 2013 at 15:06
-
2A statement like
Class<?> c = EnumClazz.class;
does not trigger the initialization ofEnumClazz
. In fact, it’s rather hard to trigger its initialization without actually using it. It’s worth emphasizing that loading and initialization are two different things.Holger– Holger2018年09月13日 13:27:34 +00:00Commented Sep 13, 2018 at 13:27