This code will work on Java 9 and above. StackWalker was added in java 9.
You can watch me work on this code on YouTube.
We can use class check to make sure, the private constructor is not accessed from any other class.
You can read entire source code at github.
To restrict the access, we can put a class check in the constructor. If the caller is a class, which is not the current class, then raise an error.
if(SingletonClass.class != walker.getCallerClass()) throw new IllegalAccessError("Private Constructor can not be invoked from outside the class");
Full Source Code :-
SingletonClass.java
public class SingletonClass{ final StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); private static SingletonClass INSTANCE; private SingletonClass(){ if(SingletonClass.class != walker.getCallerClass()) throw new IllegalAccessError("Private Constructor can not be invoked from outside the class"); } public void display(){ System.out.println("Yes I am displaying"); } public static SingletonClass instance(){ if(INSTANCE == null){ synchronized(SingletonClass.class){ if(INSTANCE == null){ INSTANCE = new SingletonClass(); } } } return INSTANCE; } }
SingletonClassTest.java -> with comments
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Constructor; public class SingletonClassTest { public static void main(final String ... args) throws InvocationTargetException, IllegalAccessException, InstantiationException { final Class<?> singletonClass = SingletonClass.class; final Constructor<?>[] arrayOfConstructors = singletonClass.getDeclaredConstructors(); final Constructor<?> privateConstructor = arrayOfConstructors[0]; privateConstructor.setAccessible(true); //final SingletonClass object = (SingletonClass) privateConstructor.newInstance(); final SingletonClass object = SingletonClass.instance(); object.display(); //final SingletonClass object1 = (SingletonClass) privateConstructor.newInstance(); //final SingletonClass object2 = (SingletonClass) privateConstructor.newInstance(); //System.out.println("object1 and object2 are the same instance " + (object1 == object2)); } }