Private Constructors
A railway station has exactly one station master's office; you can't open a second one by walking in and asking. Some classes need that kind of control over how their objects are made, or whether they're made at all. Marking a constructor private means only code inside the class can call it. Other code can't write new, and the class decides how objects come into existence.
Three Reasons to Make a Constructor Private
| Use | Example from Java itself | Idea |
|---|---|---|
| Utility class | java.lang.Math, java.util.Arrays | Only static methods; objects make no sense |
| Static factory methods | List.of(...), LocalDate.of(...) | Creation goes through named methods that can check, cache or choose |
| Singleton | A single configuration or registry object | Exactly one object for the whole program |
A Utility Class
public class Gst {
static class GstUtil {
private GstUtil() {}
static long tax(long amount, int ratePercent) {
return amount * ratePercent / 100;
}
}
public static void main(String[] args) {
System.out.println("GST on Rs. 2000: Rs. " + GstUtil.tax(2000, 18));
}
}GST on Rs. 2000: Rs. 360Line 3 makes the constructor private, so new GstUtil() from another class fails:
Priv.java:2: error: Util() has private access in Util
public class Priv { public static void main(String[] a) { new Util(); } }
^Factory Methods with Rules
public class Fares {
static class Fare {
final int km;
private Fare(int km) {
this.km = km;
}
static Fare of(int km) {
if (km <= 0) {
throw new IllegalArgumentException("Distance must be positive");
}
return new Fare(km);
}
int rupees() { return km * 2; }
}
public static void main(String[] args) {
System.out.println("300 km: Rs. " + Fare.of(300).rupees());
}
}300 km: Rs. 600Outside code can only use Fare.of(...), so every Fare goes through the check. The name of also reads better than a bare new.
A Singleton
public class Config {
static class AppConfig {
private static final AppConfig INSTANCE = new AppConfig();
final String currency = "INR";
private AppConfig() {}
static AppConfig getInstance() { return INSTANCE; }
}
public static void main(String[] args) {
AppConfig a = AppConfig.getInstance();
AppConfig b = AppConfig.getInstance();
System.out.println(a.currency + ", same object: " + (a == b));
}
}INR, same object: trueHow it works
- Line 3 creates the only
AppConfigobject when the class is loaded, and keeps it in astatic finalfield. - Line 6: the private constructor stops anyone else from making another.
- Line 8: everyone gets the same object through
getInstance(), asa == bshows.
Try it yourself: add a counter to the private constructor and call getInstance() five times. How many times does the constructor run?
Common Mistakes
Forgetting the private constructor on a utility class. The compiler adds a public one, and new GstUtil() becomes possible.
Thinking private stops all creation. Reflection can still call a private constructor; serialization and cloning also create objects. Singletons that must be bulletproof use an enum.
Making a constructor private but no factory method. Then nobody, not even you, can get an object.
Interview Corner
What is the use of a private constructor?
It stops other classes from creating objects with new. It's used for utility classes that only have static methods (like Math), for classes that create objects only through static factory methods, and for singletons that must have exactly one instance.
How do you create a singleton class in Java?
Make the constructor private, keep the single instance in a private static final field, and return it from a static getInstance() method. The simplest robust form is an enum with one constant, which also handles serialization and reflection correctly.
Practice
- Easy: Write a utility class
Tempwith a private constructor and static methodscToFandfToC. - Harder: Write a class
PinCodewith a private constructor and a factory methodof(String digits)that accepts only exactly six digits.
Key Takeaways
Was this tutorial helpful?