This,
public enum MySingleton {
INSTANCE;
}
has an implicit empty constructor. Make it explicit instead,
public enum MySingleton {
INSTANCE;
private MySingleton() {
System.out.println("Here");
}
}
If you then added another class with a main() method like
public static void main(String[] args) {
System.out.println(MySingleton.INSTANCE);
}
You would see
Here
INSTANCE
enum fields are compile time constants, but they are instances of their enum type. And, they're constructed when the enum type is referenced for the first time.
This,
public enum MySingleton {
INSTANCE;
}
has an implicit empty constructor. Make it explicit instead,
public enum MySingleton {
INSTANCE;
private MySingleton() {
System.out.println("Here");
}
}
If you then added another class with a main() method like
public static void main(String[] args) {
System.out.println(MySingleton.INSTANCE);
}
You would see
Here
INSTANCE
enum fields are compile time constants, but they are instances of their enum type. And, they're constructed when the enum type is referenced for the first time.
An enum type is a special type of class.
Your enum will actually be compiled to something like
public final class MySingleton {
public final static MySingleton INSTANCE = new MySingleton();
private MySingleton(){}
}
When your code first accesses INSTANCE, the class MySingleton will be loaded and initialized by the JVM. This process initializes the static field above once (lazily).
What are the downsides of implementing a singleton with Java's enum? - Software Engineering Stack Exchange
Implementing Singleton as enum?
java - Singleton using enum - Code Review Stack Exchange
java - How to create a singleton class using enum - Stack Overflow
Videos
Some problems with enum singletons:
Committing to an implementation strategy
Typically, "singleton" refers to an implementation strategy, not an API specification. It is very rare for Foo1.getInstance() to publicly declare that it'll always return the same instance. If needed, the implementation of Foo1.getInstance() can evolve, for example, to return one instance per thread.
With Foo2.INSTANCE we publicly declare that this instance is the instance, and there's no chance to change that. The implementation strategy of having a single instance is exposed and committed to.
This problem is not crippling. For example, Foo2.INSTANCE.doo() can rely on a thread local helper object, to effectively have a per-thread instance.
Extending Enum class
Foo2 extends a super class Enum<Foo2>. We usually want to avoid super classes; especially in this case, the super class forced on Foo2 has nothing to do with what Foo2 is supposed to be. That is a pollution to the type hierarchy of our application. If we really want a super class, usually it's an application class, but we can't, Foo2's super class is fixed.
Foo2 inherits some funny instance methods like name(), cardinal(), compareTo(Foo2), which are just confusing to Foo2's users. Foo2 can't have its own name() method even if that method is desirable in Foo2's interface.
Foo2 also contains some funny static methods
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
which appears to be nonsensical to users. A singleton usually shouldn't have pulbic static methods anyway (other than the getInstance())
Serializability
It is very common for singletons to be stateful. These singletons generally should not be be serializable. I can't think of any realistic example where it makes sense to transport a stateful singleton from one VM to another VM; a singleton means "unique within a VM", not "unique in the universe".
If serialization really does make sense for a stateful singleton, the singleton should explicitly and precisely specify what does it means to deserialize a singleton in another VM where a singleton of the same type may already exist.
Foo2 automatically commits to a simplistic serialization/deserialization strategy. That is just an accident waiting to happen. If we have a tree of data conceptually referencing a state variable of Foo2 in VM1 at t1, through serialization/deserialization the value becomes a different value - the value of the same variable of Foo2 in VM2 at t2, creating a hard to detect bug. This bug won't happen to the unserializable Foo1 silently.
Restrictions of coding
There are things that can be done in normal classes, but forbidden in enum classes. For example, accessing a static field in the constructor. The programmer has to be more careful since he's working in a special class.
Conclusion
By piggybacking on enum, we save 2 lines of code; but the price is too high, we have to carry all the baggages and restrictions of enums, we inadvertently inherit "features" of enum that have unintended consequences. The only alleged advantage - automatic serializability - turns out to be a disadvantage.
An enum instance is dependant on the class loader. ie if you have a second class loader that does not have the first class loader as a parent loading the same enum class you can get multiple instances in memory.
Code Sample
Create the following enum, and put its .class file into a jar by itself. ( of course the jar will have the correct package/folder structure )
package mad;
public enum Side {
RIGHT, LEFT;
}
Now run this test, making sure that there is no copies of the above enum on the class path:
@Test
public void testEnums() throws Exception
{
final ClassLoader root = MadTest.class.getClassLoader();
final File jar = new File("path to jar"); // Edit path
assertTrue(jar.exists());
assertTrue(jar.isFile());
final URL[] urls = new URL[] { jar.toURI().toURL() };
final ClassLoader cl1 = new URLClassLoader(urls, root);
final ClassLoader cl2 = new URLClassLoader(urls, root);
final Class<?> sideClass1 = cl1.loadClass("mad.Side");
final Class<?> sideClass2 = cl2.loadClass("mad.Side");
assertNotSame(sideClass1, sideClass2);
assertTrue(sideClass1.isEnum());
assertTrue(sideClass2.isEnum());
final Field f1 = sideClass1.getField("RIGHT");
final Field f2 = sideClass2.getField("RIGHT");
assertTrue(f1.isEnumConstant());
assertTrue(f2.isEnumConstant());
final Object right1 = f1.get(null);
final Object right2 = f2.get(null);
assertNotSame(right1, right2);
}
And we now have two objects representing the "same" enum value.
I agree that this is a rare and contrived corner case, and almost always an enum can be used for a java singleton. I do it myself. But the question asked about potential downsides and this note of caution is worth knowing about.
In Effective Java 2nd Edition, Joshua Bloch recommends implementing singleton using ENUM with a single item:
As of release 1.5, there is a third approach to implementing singletons. Simply make an enum type with one element:
// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.
While this practice solves some of the pitfalls of singletons, I always felt it is misuse and abuse of Enum construct for something that it was not intended for? What do you thing about this approach?
No, it is simpler to code than that:
enum Singleton
{
INSTANCE;
// instance vars, constructor
private final Connection connection;
Singleton()
{
// Initialize the connection
connection = DB.getConnection();
}
// Static getter
public static Singleton getInstance()
{
return INSTANCE;
}
public Connection getConnection()
{
return connection;
}
}
Then you use can use final Singleton s = Singleton.getInstance(). Note however that since this is an enum you can always access this via Singleton.INSTANCE.
And NEVER do that:
public Singleton getInstance(){
if(s==null)
return new Singleton();
else return s;
}
this is not thread safe! What is more, the new Singleton() value is never assigned to s... (thanks @DaveJarvis for noticing this!)
public enum Singleton{
INSTANCE;
}
This is enough; you can directly use Singleton.INSTANCE to get the instance of the class.
The differences between a class and an enum are not so big. I changed the first line of code to public enum instead of public class and added the name of your instance.
public enum Employee { // changed "class" to "enum"
INSTANCE; // added name of the (single) instance
private int id;
private String name;
Employee() {} // removed "public"
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
}
Please keep in mind, that singeltons, enum instances, static things might hinder you later on, if you want to run your code several times in one vm. Consider creating an instance of Employee in your main class and pass it through your application.
Beside that, enums have some other special features:
- You cannot
extendanother class (onlyimplements) - Some predefined methods (like
static values()andgetName()) are available - constructors can only be package private, or private
Your "Employee" class isn't really something that should be a singleton, but here goes.
public enum Employee {
INSTANCE;
private int id;
private String name;
private Employee() {} //enum constructor must be private
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
}
Then you can do
Employee.INSTANCE.setName("Hello World!");