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.