Design a class such that only one instance of the class and any of its sub-classes can be created. To clarify: Assume A is such a class and B is derived from A. B does not have any special code apart from extending A.
class A { // code of class A } public class B extends A{ public static void main(String[] args) { new A(); // works fine. new A(); // causes an exception new B(); // works fine as this is the first instance of B new B(); // causes an exception. } }
But we need to create the object with the new keyword.
I try in static value define in parent but this does not help.
Advertisement
Answer
class A { private static Map<Class<? extends A>, A> instances = new HashMap<>(); public A() { synchronized (A.class) { if (instances.containsKey(this.getClass())) { throw new IllegalStateException(); } instances.put(getClass(), this); } } // code of class A } public class B extends A { public static void main(String[] args) { new A(); // works fine. new A(); // causes an exception new B(); // works fine as this is the first instance of B new B(); // causes an exception. } }
When you create an instance of A
or any subclass of A
, the constructor of A
it is called.
The constructor checks if an instance of A
is present in the Map
instances
.
If an instance of the current class exists, an exception is thrown.
If no instance of the current class exists (when no exception is thrown), the current object is saved to instances
.
The Map
is static
so the same Map
is used across all instances (It obviously would not work if every instance of A
had its own Map
).
The synchronized
block makes sure that the map access is thread safe by locking the Class
object of A
. Locking the current Class
object is not thread safe as the put
method of HashMap
is not thread safe when creating new objects.
You can also lock instances
or use a Set
of Class
es as described in this answer from oleg.cherednik.