Private Constructor in Java – Uses and Examples
A private constructor is a constructor that can only be called from inside its own class. Other classes cannot write new MyClass(). That sounds odd at first, but it is how Java controls who creates objects and how many are created.
This tutorial explains the main uses of private constructors, utility classes, singletons, static factory methods and enums, with runnable examples, and shows how they affect inheritance.
1. What a Private Constructor Does
Marking a constructor private means only code in the same class (including its nested classes) can call it. Any other class gets a compile error:
Main.java:2: error: Config() has private access in Config
public class Main { public static void main(String[] a) { new Config(); } }
^
1 error
The class decides for itself when objects are created, usually through a static method.
2. Use 1: Utility Classes
A class that contains only static methods and constants, such as java.lang.Math or java.util.Collections, should never be instantiated. A private constructor makes that impossible, and throwing an AssertionError inside it also stops accidental calls from within the class:
public class UtilityClass {
// A utility class: only static members, never instantiated
static final class MathUtils {
private MathUtils() {
throw new AssertionError("MathUtils cannot be instantiated");
}
static int square(int n) { return n * n; }
static boolean isEven(int n) { return n % 2 == 0; }
}
public static void main(String[] args) {
System.out.println("square(7) = " + MathUtils.square(7));
System.out.println("isEven(10) = " + MathUtils.isEven(10));
// new MathUtils(); // would compile here (same outer class) but throws AssertionError
}
}
square(7) = 49 isEven(10) = true
Without the private constructor, the compiler would add a public default constructor and new MathUtils() would compile everywhere.
3. Use 2: The Singleton Pattern
A singleton is a class with exactly one instance, such as a configuration registry or a connection manager. The private constructor prevents extra instances, and a static method returns the single one:
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private int requests;
private Singleton() { // nobody else can call new Singleton()
System.out.println("Singleton created");
}
public static Singleton getInstance() { return INSTANCE; }
public int handleRequest() { return ++requests; }
public static void main(String[] args) {
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
a.handleRequest();
System.out.println("requests seen by b: " + b.handleRequest());
System.out.println("same instance: " + (a == b));
}
}
Singleton created requests seen by b: 2 same instance: true
Here the instance is created eagerly when the class loads, which is simple and thread-safe. Singletons create hidden global state, so use them sparingly; dependency injection frameworks such as Spring manage single instances for you.
4. Use 3: Static Factory Methods
Constructors all share the class's name, so two constructors taking one double cannot be told apart. With a private constructor and named static factories, each way of creating an object gets a clear name:
public class FactoryMethods {
static final class Temperature {
private final double celsius;
private Temperature(double celsius) { this.celsius = celsius; }
// Named static factories are clearer than overloaded constructors with the same parameter type
static Temperature ofCelsius(double c) { return new Temperature(c); }
static Temperature ofFahrenheit(double f) { return new Temperature((f - 32) * 5 / 9); }
static Temperature ofKelvin(double k) { return new Temperature(k - 273.15); }
@Override public String toString() { return String.format("%.1f °C", celsius); }
}
public static void main(String[] args) {
System.out.println(Temperature.ofCelsius(25));
System.out.println(Temperature.ofFahrenheit(98.6));
System.out.println(Temperature.ofKelvin(300));
}
}
25.0 °C 37.0 °C 26.9 °C
Factories can also return cached instances (Integer.valueOf()), choose a subclass (List.of()), or validate input before creating anything. The JDK uses this style widely: LocalDate.of(), Optional.of(), Path.of().
5. Use 4: Enums
Enum constructors are always private, whether or not you write the keyword. Only the constants listed in the enum can ever exist, which makes a single-constant enum the simplest and safest way to write a singleton:
public class EnumSingleton {
// Enum constructors are always private; an enum with one constant is a simple, safe singleton
enum AppConfig {
INSTANCE;
private final String environment;
AppConfig() { // implicitly private
environment = "production";
}
String environment() { return environment; }
}
public static void main(String[] args) {
System.out.println(AppConfig.INSTANCE.environment());
System.out.println(AppConfig.INSTANCE == AppConfig.valueOf("INSTANCE"));
}
}
production true
Enum singletons are protected against reflection and serialization tricks that can break a class-based singleton.
6. Private Constructors and Inheritance
- A subclass constructor must call a parent constructor. If all of the parent's constructors are private, no outside class can extend it, so a private constructor effectively makes the class non-extendable.
- Nested classes are an exception: they can call the outer class's private constructor, so a class can allow subclasses only inside itself.
- To clearly prevent inheritance, also declare the class
final; or usesealedclasses (Java 17) to list exactly which subclasses are allowed.
7. Other Uses
- Builder pattern: the class has a private constructor that takes a builder; users must go through
Builder.build(). - Constant classes: classes holding only
static finalconstants. - Controlled instance pools: classes that limit or cache the objects they hand out.
- Constructor helpers: a private constructor called by public constructors through
this(...).
8. Summary
- A private constructor can only be called from inside its own class.
- Use it for utility classes, singletons, static factory methods and builders.
- Enum constructors are always private.
- A class whose constructors are all private cannot be extended from outside.
- Prefer enum singletons or dependency injection over hand-written singletons when possible.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a private constructor in Java?
A constructor declared with the private access modifier. Only code inside the same class can call it, so other classes cannot create objects with new.
Q2. Why would you make a constructor private?
To prevent instantiation of utility classes, to control the number of instances (singletons), to force creation through named factory methods or builders, or to stop other classes from extending the class.
Q3. Can a class with a private constructor be instantiated?
Yes, but only from inside the class itself, typically by a static method such as getInstance() or of(). Reflection can also bypass it unless prevented.
Q4. Can a class with a private constructor be inherited?
Not by outside classes, because a subclass must be able to call a parent constructor. Nested classes inside it can extend it.
Q5. How do I create a singleton in Java?
The simplest safe ways are a private constructor with a private static final instance and a static getter, or an enum with a single constant.
Q6. Why is an enum singleton recommended?
The JVM guarantees each enum constant is created once, it is thread-safe, and it cannot be duplicated through reflection or serialization.
Q7. Are enum constructors private?
Yes, always. Writing private is optional, and declaring them public or protected is a compile error.
Q8. What is a utility class?
A class containing only static methods and constants, such as Math, Arrays or Collections. It should have a private constructor so no instances are created.
Q9. Why throw an exception inside a private constructor?
To stop accidental instantiation from inside the class itself or through reflection. AssertionError is a common choice because creating an instance indicates a programming error.
Q10. What is a static factory method?
A static method that returns an instance of its class, such as LocalDate.of(2026, 10, 11). Unlike constructors, factories have descriptive names and can return cached objects or subclasses.
Q11. Can a class have both public and private constructors?
Yes. Public constructors can delegate shared work to a private one with this(...).
Q12. Can an abstract class have a private constructor?
Yes, but then only nested classes can extend it. This is sometimes used to create a closed set of subclasses, although sealed classes are now a clearer way to do that.
Q13. Can reflection call a private constructor?
Yes, with setAccessible(true), unless the module system blocks it or the constructor throws an exception. Enum constructors cannot be invoked through reflection.
Q14. Is a singleton thread-safe?
Eager initialisation (private static final INSTANCE = new ...) and enum singletons are thread-safe. Lazy initialisation needs care, for example the holder-class idiom or double-checked locking with volatile.
Q15. What is the difference between private constructor and final class?
A final class cannot be extended but can still be instantiated. A class with only private constructors cannot be instantiated or extended from outside. Utility classes often use both.
Q16. How does the builder pattern use private constructors?
The main class has a private constructor that accepts a builder object. Users configure a Builder and call build(), which is the only way to create the object.
Q17. What happens if a class has no constructor at all?
The compiler adds a public default constructor (matching the class's access). That is why utility classes need an explicit private constructor.
Q18. Which JDK classes have private constructors?
Math, Collections, Arrays, Objects, System and many others in java.util and java.lang.
Q19. Can a private constructor be overloaded?
Yes. A class can have several private constructors with different parameters, used by its own factory methods.
Q20. Do records allow private constructors?
No. A record's canonical constructor must be at least as accessible as the record itself. Use a compact constructor for validation, or a static factory alongside it.