Overloaded Constructors
Before You Start
Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.
Not sure? Take the 60-second self-check.
1. Overload resolution. Two methods: void m(String s) and void m(int i). Which is called by m("hello")?
Check
void m(String s). The compiler selects the overload whose parameter types match the argument types at the call site.
2. Signature. What defines the signature of a constructor?
Check
The parameter count and the parameter types, in order. The class name is the same for all constructors; the signature is what distinguishes them.
3. No-arg constructor. If a class declares no constructor at all, what constructor does Java provide?
Check
A default no-argument constructor that calls super() implicitly. If any constructor is declared, the default no-arg constructor is NOT provided.
Try This First
S20.Lab3.Book has two constructors. One takes (String, String, int, Genre, Publisher, String[]) and another takes (String, String, int, String, String, String, Author[]). Which constructor is called by:
new Book("Java", "ISBN123", 400, Genre.NONFICTION, somePublisher, new String[]{"Bloch"})
Check
The first constructor: the argument types match (String, String, int, Genre, Publisher, String[]). The compiler picks the overload whose parameter types align with the argument types.
What You Need To Walk In With
The Insight: Multiple constructors serve different call sites that have the data in different formats. The compiler distinguishes them by parameter types (the signature), not by name (all constructors share the class name) and not by parameter name. Each overloaded constructor is a different entry point to the same fully-formed object.
If the dispatch rule feels uncertain, write out the argument types explicitly and match them one by one against each constructor’s parameter types. The match must be exact (or an implicit widening conversion). That mechanical step is all the compiler does.
You can: identify which constructor a call dispatches to, predict the compile error when no overload matches, explain why two same-signature constructors are illegal, and state when static factory methods are a cleaner alternative.
How It Works
S20 Lab 3 Book: two EVCs for two caller formats
// EVC 1: caller has Genre enum and Publisher object
public Book(final String title, final String isbn, final int pages,
final Genre type, final Publisher pubs, final String[] author) { ... }
// EVC 2: caller has raw String data (e.g., from a CSV file)
public Book(final String title, final String isbn, final int pages, final String type,
final String pubName, final String pubCity, final Author[] array) { ... }
A client reading from a file passes raw strings. A client working in-memory passes objects. Both result in the same fully-initialized Book. Neither client has to massage their data into the other’s format.
Overload resolution rules (JLS §15.12.2)
The compiler finds the most specific applicable overload. For constructors:
- Find all overloads whose parameter types are compatible with the argument types.
- Among those, pick the most specific one.
- If no overload matches, or if multiple overloads are equally specific, report a compile error.
Signatures must differ by type
Two constructors that differ only in parameter names (not types) have the same signature and produce a “duplicate constructor” error:
// ILLEGAL: identical signature (String, String)
public Book(String title, String isbn) { ... }
public Book(String isbn, String title) { ... } // same as above
For this case, static factory methods are the correct solution (Bloch, Effective Java, Item 1): Book.byTitleAndIsbn(...), Book.byIsbnAndTitle(...).
Worked Example: Predict Then Check
For each new Book(...) call, state which constructor is invoked or state “compile error”:
// (a)
new Book("T", "I", 100, Genre.FICTION, pub, new String[]{"A"})
// (b)
new Book("T", "I", 100, "fiction", "Pearson", "Boston", authorArray)
// (c)
new Book("T")
// (d)
new Book("T", "I", 100, Genre.FICTION, pub, authorArray) // authorArray is Author[]
Show answer
(a) EVC 1: argument types match (String, String, int, Genre, Publisher, String[]).
(b) EVC 2: argument types match (String, String, int, String, String, String, Author[]).
(c) Compile error: no constructor accepts one String argument.
(d) Compile error: the sixth argument is Author[], but EVC 1’s sixth parameter is String[] and EVC 2’s seventh parameter is Author[] (with a different number of arguments). No matching overload.
Source: S20.Lab3.Book.java.
Quick check
Check your understanding
A class has two constructors: Widget(String label, int count) and Widget(int count, String label). Which constructor does new Widget(“done”, 3) call, or is it a compile error?
Common Misconceptions
Misconception 1: two constructors with the same parameter types but different parameter names are allowed
Wrong mental model: “I have
Book(String title, String isbn)andBook(String isbn, String title)(different names, both seemingly useful).”
Why it breaks: The compiler matches by type, not name. Both constructors have signature (String, String). This is a duplicate signature. Compile error: “constructor Book(String, String) is already defined.”
How to correct: Use static factory methods with descriptive names. Book.byTitleAndIsbn(...) and Book.byIsbnAndTitle(...) convey the intent and avoid the signature collision.
Source: JLS §8.8.2; Bloch, Effective Java, Item 1.
Quick check
Check your understanding
A class declares Person(String firstName, String lastName) and Person(String lastName, String firstName). What is the result?
Misconception 2: always use multiple constructors instead of factory methods
Wrong mental model: “I need three ways to create a Book; three constructors is the right design.”
Why it matters: Constructors all share the class name. With three or more, callers must read parameter type lists to determine which does what. Named factory methods carry intent in their names: Book.fromCsv(...), Book.fromJsonObject(...). Steiner labs use multiple EVCs to teach the constructor overloading mechanic; in production code, factories are often cleaner for three or more variants.
How to correct: Limit constructors to cases where the caller’s data format is clearly distinct from the parameter types. For three or more variations, prefer static factory methods.
Source: Bloch, Effective Java, Item 1.
Formal Definition and Interface Contract
From JLS §8.8.2 (Constructor Signature):
It is a compile-time error if two constructors of the same class have the same signature (name and parameter types).
From JLS §15.12.2 (Find Methods to Invoke):
The first phase (§15.12.2.2) searches for constructor declarations [...] without permitting boxing or unboxing conversion, and without permitting the use of variable arity method invocation. [...] If no applicable method is found, the second phase (§15.12.2.3) is performed.
Mental Model
Think of constructors as different loading docks at a warehouse. Each dock accepts a specific format of delivery (one dock for pallets, another for small parcels). The warehouse (the class) is the same; only the input format differs. The compiler, like a routing system, reads the package label (the argument types) and directs traffic to the right dock (the matching constructor signature).
Connections
Within CSCD 210/211: S20.Lab3.Book is the canonical CSCD 211 example. F17.Lab6.Engine, SP18.Lab2.Vehicle, SP19.Lab9.Engine, and W18.Lab1.Motor all use two-EVC patterns with argument-reorder delegation (covered in this(...) Constructor Delegation).
Looking back: The field-declaration and null-check lessons covered what each constructor must do. This lesson covers what happens when there are multiple constructors.
Looking ahead: this(...) Constructor Delegation covers how one constructor can delegate to another via this(...) to eliminate duplication.
Go Deeper (optional)
None of what follows is needed to write correct, well-tested Java. Read it because you are curious, not because you feel you must.
The two-EVC pattern in S20.Lab3.Book is easy to spot in professional codebases: a constructor that accepts domain objects (already typed and validated) alongside one that accepts raw strings (from a file or network). What is less obvious is that Bloch’s Item 1 in Effective Java documents four specific reasons static factory methods can replace or supplement this pattern: they carry descriptive names (a Book(String, String) constructor tells you nothing; Book.fromCsvLine(String) tells you everything); they need not create a new object on every call (a factory can cache or pool); they can return any subtype of the declared return type; and they reduce the verbosity of parameterized types. These four reasons are worth knowing because they surface in technical interviews and code reviews.
At a deeper level, the overload dispatch rule here is the same mechanism that underlies the Comparator and Comparable design: passing a function object (a Comparator) to a sort method is a form of overloading at the type level. That object encapsulates one sorting strategy, which is exactly the Strategy pattern (described in the Gang of Four, 1994). The idea that behavior can be packaged as an object and passed in is one step away from first-class functions, the concept that Java formalized with lambda expressions in Java 8. So the two-EVC Book constructor is not just a lab exercise; it is a small window into the design-pattern and language-evolution story that runs through the whole Java ecosystem.
In professional Java code, most classes expose one primary constructor and route format-specific creation through named static factories. You will see this in every major Java library, including the JDK itself: Integer.valueOf(String), List.of(...), Path.of(String, String...). Recognizing this pattern on sight is the mark of someone who has read production code.
Practice
Level 1
A Motor class has two constructors: Motor(String manufacturer, double watts) and Motor(double watts, String manufacturer). Which is called by new Motor("GE", 500.0) and which by new Motor(500.0, "GE")?
Show answer
new Motor("GE", 500.0) calls Motor(String, double) (first argument is String).
new Motor(500.0, "GE") calls Motor(double, String) (first argument is double).
Pattern from W18.Lab1.Motor.
Level 2
Explain why the following class does not compile and provide the correct fix:
public class Person {
public Person(String firstName, String lastName) { ... }
public Person(String lastName, String firstName) { ... }
}
Show answer
Both constructors have signature (String, String). Duplicate signatures are illegal (JLS §8.8.2). The compiler reports “constructor Person(String, String) is already defined.”
Fix: Use a static factory method for one or both:
public static Person withFirstNameFirst(String firstName, String lastName) {
return new Person(firstName, lastName);
}
public static Person withLastNameFirst(String lastName, String firstName) {
return new Person(firstName, lastName);
}
private Person(String firstName, String lastName) { ... }
Source: Bloch, Effective Java, Item 1.
Level 3
S20.Lab3.Book has two EVCs: one takes a Genre enum and a Publisher object; the other takes String forms of those. Explain why this design exists (what caller contexts require it) and identify one alternative that modern Java would offer.
Show answer
The first EVC serves callers who already have domain objects: they have a Genre constant from user input and a Publisher from a lookup. The second EVC serves callers reading from a flat file or CSV: the data arrives as raw strings and needs to be parsed into the domain objects inside the constructor.
The alternative: static factory methods. Book.fromCsvLine(String line) parses the line and calls one canonical constructor. Book.fromDomainObjects(Genre g, Publisher p, ...) calls the same canonical constructor. Both methods converge on one constructor with guaranteed preconditions, and each factory method carries a descriptive name that tells the caller exactly what input format it expects.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
What does Java use to distinguish two constructors in the same class?
A class Book has these two constructors: Book(String title, String isbn) and Book(String isbn, String title). What happens at compile time?
Given these two constructors: Book(String title, String isbn, int pages, Genre type, Publisher pubs, String[] author) and Book(String title, String isbn, int pages, String type, String pubName, String pubCity, Author[] array). Which constructor does this call dispatch to, or is it a compile error? new Book(“Java”, “ISBN1”, 400, Genre.NONFICTION, somePublisher, new String[]{“Bloch”})
S20.Lab3.Book has two EVCs: one accepts a Genre enum and a Publisher object; the other accepts raw String values for those fields. Why does this design exist?
A class has constructor Motor(String manufacturer, double watts) and Motor(double watts, String manufacturer). State which constructor is called by each: (a) new Motor(“GE”, 500.0) (b) new Motor(500.0, “GE”) (c) new Motor(“GE”)