What are the limitations of providing only static factory methods, and how would you decide between a factory and a public constructor?
answer
- Private ctor + factories ⇒ no subclassing (no super())
- Blessing in disguise → composition over inheritance
- Factories less discoverable than constructors in Javadoc
- Factory: name / instance control / hide impl / vary type
- Constructor: subclassing, single obvious build, frameworks
basics
~20 sThe two main downsides: a class with only static factories and a private constructor can't be subclassed, and factories are harder to find in the docs than constructors. Use a factory when you want a clear name, instance control, or to hide the concrete type; keep a constructor when subclassing matters.
solid answer
~50 sStatic factories have two well-known limitations. First, if you provide only factories and make the constructor private or package-private, the class effectively can't be subclassed, because subclasses have no constructor to call via super(). Bloch calls this a blessing in disguise since it encourages composition over inheritance, but it's a genuine constraint if extension is a real requirement. Second, factories are harder to discover than constructors: Javadoc gives constructors a dedicated section, whereas a factory is just one method among many, so users may not realize how to instantiate the class — mitigate with clear class docs and standard names. To decide: reach for a factory when you want a meaningful name, instance control (caching/singletons), to return an interface and hide the implementation, or to vary the returned type by input. Keep a public constructor when you want the class to be subclassable, when there's a single obvious construction with no naming ambiguity, or for framework/reflection requirements that expect a no-arg constructor.
go deeper
Knows the two headline limitations exist (no subclassing, harder to find) even if they can't fully justify the subclassing one.
Explains why a private constructor blocks subclassing (super() needs an accessible constructor) and lists mitigations for discoverability.
Gives a balanced decision framework for factory vs constructor, weighing instance control and impl-hiding against subclassing and framework needs.
Frames the choice as an API-evolution commitment, recognizes that both can coexist (protected ctor + factory), and sets team-wide guidance on when each is appropriate.
## The trade-off side of the idiom *Effective Java* presents static factories as something to *consider first*, not a universal rule — because they carry two real limitations. ### Limitation 1: classes without public/protected constructors can't be subclassed The usual factory pattern makes the constructor **`private`** (or package-private) so callers must go through the factory — that's how you get **instance control**. But subclassing in Java requires a subclass constructor to invoke a superclass constructor via **`super(...)`**, and it can only call a constructor that is **accessible** (public or protected). With no accessible constructor, **no subclass can be written**. So a fully factory-driven class is effectively un-extendable by inheritance. Bloch argues this is often a **blessing in disguise**: it pushes designers toward **composition and delegation** rather than fragile inheritance hierarchies, and it's a prerequisite for immutable and value types anyway. But when extensibility via inheritance is a legitimate design goal, this is a true cost — you'd then expose a protected/public constructor (and lose some instance control). ### Limitation 2: factories are hard to find A **constructor** has a prominent, dedicated place in generated documentation ('Constructor Summary'). A **static factory** is just another entry in the method list, so a developer reading the API may not realize the class is instantiated via, say, `getInstance()` rather than `new`. Mitigations: - Follow the **naming conventions** (`of`/`valueOf`/`getInstance`/`from`...), which readers recognize. - Call out the factories prominently in the **class-level Javadoc**. - Be consistent across the codebase so the team expects factories. ### Secondary considerations - **Frameworks expecting a no-arg constructor.** Some serialization/reflection/bean frameworks instantiate via a public no-arg constructor; a factory-only class can be awkward there (though many modern frameworks support factory methods). - **Static methods aren't inherited the way you'd want.** A static factory on a superclass isn't polymorphic — it doesn't 'override' in subclasses — so factory-heavy hierarchies can be confusing. ## A decision checklist Prefer a **static factory** when you want one or more of: - a **meaningful name** (or multiple construction paths with the same parameter types), - **instance control** — caching, singletons, interning, or the `equals`⇔`==` value guarantee, - to **return an interface / hide the concrete class** (interface-based API, swappable implementation), - to **choose the returned class by input** (e.g. `EnumSet.of`), - **service-provider** plug-in style where the class may not yet exist. Prefer (or also keep) a **public constructor** when: - the class is **designed for subclassing**, - there's **exactly one obvious construction** and a factory adds no clarity or control, - you need to satisfy **frameworks/tools that require an accessible constructor** (some DI, serialization, reflection). ## Nuance for principals The two aren't mutually exclusive — a class can expose both, or expose a protected constructor for subclassing while steering ordinary callers to a factory. The deeper point is **what you want to be able to change later**: factories that return interfaces preserve your freedom to evolve implementations; public constructors that pin a concrete class give that freedom away. Treat 'constructor vs factory' as an **API-commitment decision**, not just a style choice.
- Why exactly can't a class with only a private constructor be subclassed?A subclass constructor must call a superclass constructor via super(...). super() can only invoke an accessible constructor (public or protected). A private constructor is inaccessible to subclasses, so no subclass can be compiled. This is intrinsic to how Java initializes the inheritance chain.
- Is choosing a factory over a constructor purely a style decision?No — it's an API-commitment decision. A factory returning an interface keeps the concrete implementation hidden, so you can change it in future releases without breaking callers. A public constructor pins a specific class into the public API, surrendering that flexibility. The choice shapes how the type can evolve.
saying these in an interview costs you the question
- Claiming static factories have no downsides — missing the subclassing and discoverability costs.
- Saying a private constructor can still be called by subclasses via super() — it can't; access rules block it.
- Treating 'always use factories' as an absolute rule rather than a 'consider first' guideline.
- Forgetting that some frameworks (serialization/DI/reflection) may require an accessible no-arg constructor.