Constructor Injection vs Setter Injection
Compare constructor injection and setter injection in Java: immutability, required vs optional dependencies, and when to use each.
Expected Interview Answer
Constructor injection supplies dependencies as constructor parameters so an object is fully and immutably initialized the instant it is created, while setter injection supplies dependencies through public setter methods called after construction, allowing optional or later-configurable dependencies but permitting a temporarily incomplete object.
Constructor injection makes required dependencies explicit in the type’s public API: you cannot instantiate the class without supplying them, and fields can be declared final, giving compile-time and runtime immutability guarantees. Setter injection is more flexible for optional collaborators, circular dependency scenarios, or configuration that changes after startup, but it means an object can exist, briefly or indefinitely, without all its dependencies set, risking null-pointer failures if a setter call is missed. Most dependency-injection frameworks, including Spring, recommend constructor injection as the default and reserve setter injection for genuinely optional dependencies. Constructor injection also makes unit testing simpler, since a test can pass mocks directly into the constructor without relying on the container.
- Constructor injection: guarantees complete, immutable, testable objects
- Setter injection: supports optional and reconfigurable dependencies
- Constructor injection surfaces required dependencies in the public API
- Setter injection helps break certain circular-dependency wiring issues
AI Mentor Explanation
A batter who must have their bat handed to them before stepping onto the field, with no way to walk out without it, mirrors constructor injection: the dependency is mandatory and fixed before the object (the batter, ready to play) exists in a usable state. A fielder who can optionally put on sunglasses partway through a session, or skip them entirely, mirrors setter injection: the dependency can be added, changed, or left unset after play has already begun without breaking anything essential.
Step-by-Step Explanation
Step 1
List required vs optional dependencies
Separate what the object cannot function without from what it can live without.
Step 2
Inject required dependencies via constructor
Pass mandatory dependencies as constructor parameters, ideally into final fields.
Step 3
Inject optional dependencies via setters
Expose setters only for collaborators that have sensible defaults or may change.
Step 4
Verify object validity
A constructed object should never be usable in an invalid, partially wired state.
What Interviewer Expects
- A clear articulation of the immutability vs flexibility trade-off
- Knowledge that most frameworks default to constructor injection
- Awareness that setter injection can leave objects partially initialized
- Mention of testability differences between the two approaches
Common Mistakes
- Claiming setter injection is always worse with no valid use cases
- Not mentioning that constructor injection enables final/immutable fields
- Assuming both approaches are functionally identical
- Forgetting that setter injection can help resolve certain circular dependencies
Best Answer (HR Friendly)
“Constructor injection means you hand an object everything it truly needs right when you create it, so it is always ready to use and its dependencies cannot be changed afterward. Setter injection means you create the object first and then optionally configure it afterward through method calls. I default to constructor injection for anything required, and use setter injection only for genuinely optional settings.”
Code Example
class ReportGenerator {
private final DataSource dataSource; // required, immutable
private Formatter formatter; // optional, has a default
// Constructor injection: mandatory dependency
ReportGenerator(DataSource dataSource) {
this.dataSource = dataSource;
this.formatter = new PlainTextFormatter(); // sensible default
}
// Setter injection: optional dependency, can override the default
void setFormatter(Formatter formatter) {
this.formatter = formatter;
}
String generate() {
return formatter.format(dataSource.fetch());
}
}Follow-up Questions
- Why do frameworks like Spring recommend constructor injection by default?
- How can setter injection help break a circular dependency?
- What happens if a required setter is never called?
- Can you mix constructor and setter injection in the same class?
MCQ Practice
1. Which approach allows fields to be declared final?
Constructor injection assigns dependencies once at construction, allowing fields to be declared final for immutability.
2. A risk unique to setter injection is?
Because setter calls are separate from construction, a required setter can be forgotten, leaving the object incomplete.
3. Most modern DI frameworks recommend which style as the default?
Constructor injection is the recommended default because it produces complete, immutable, and easily testable objects.
Flash Cards
Constructor injection in one line? — Dependencies passed as constructor parameters, making the object valid immediately and enabling immutability.
Setter injection in one line? — Dependencies assigned via public setters after construction, suited to optional or reconfigurable collaborators.
Which is generally preferred and why? — Constructor injection, because it guarantees required dependencies and supports final fields.
One legitimate use for setter injection? — Breaking a circular dependency or configuring a genuinely optional collaborator.