skip to content

When does the Java compiler NOT generate the default no-arg constructor, and what problem can that cause?

level: middleimportance: must knowfreq 78%

answer

  1. ANY declared constructor kills the freebie
  2. even private/parameterized counts
  3. subclass implicit super() needs parent no-arg ctor
  4. frameworks need no-arg → re-add it
  5. fix: declare the no-arg ctor explicitly

basics

~20 s

As soon as you write any constructor of your own — even one that takes parameters — the compiler stops adding the free no-arg one. Then new MyClass() won't compile unless you also write the no-arg constructor yourself.

solid answer

~40 s

The compiler generates the implicit no-arg constructor only when a class declares zero constructors. The instant you write *any* constructor — most commonly a parameterized one — that freebie disappears. So a class with only `Person(String name)` has no no-arg constructor, and `new Person()` fails to compile. This bites in two classic ways. First, subclasses: a child constructor implicitly calls `super()`, so if the parent only has a parameterized constructor, every child constructor must explicitly call `super(arg)` or it won't compile. Second, frameworks: JPA/Hibernate, Jackson, and many reflection-based tools require a no-arg constructor to instantiate objects; adding a parameterized constructor and forgetting to re-add the no-arg one is a frequent production break. The fix is simply to declare the no-arg constructor explicitly when you still need it.

code

java · 14 lines
java
class Person {
    private final String name;
    public Person(String name) { this.name = name; }
}

// Person p = new Person();        // COMPILE ERROR: no no-arg constructor
Person p = new Person("Ada");      // OK

// Inheritance trap:
class Employee extends Person {
    public Employee(String name) {
        super(name);                // REQUIRED — Person has no no-arg ctor,
    }                               // so implicit super() would not compile
}

go deeper

for a junior

Knows that writing a parameterized constructor means new MyClass() no longer compiles unless you add the no-arg one.

for a middle

Explains the binary rule (any declared ctor suppresses the default), the implicit super() consequence for subclasses, and re-adding the no-arg ctor.

for a senior

Diagnoses the framework angle (JPA/Jackson InstantiationException), recommends a protected no-arg ctor for entities, and reasons about invariants.

for a principal

Sets team conventions: when to force construction through args to protect invariants vs. provide tooling-friendly no-arg ctors, and how this interacts with immutability and builders.

## The single rule Java's compiler inserts the **implicit default constructor** (public-or-class-matching, no-argument, body `super();`) **only when the class declares no constructors whatsoever**. This is binary: zero declared constructors → you get the freebie; one or more declared → you get nothing extra. ```java class A { } // gets implicit A() class B { B(int x) { } } // NO implicit no-arg ctor; new B() fails class C { C() { } C(int x) { } } // you wrote both; both exist ``` Note it does **not** matter whether the constructor you wrote is no-arg or parameterized, public or private — *any* declared constructor turns the generator off. Even a single `private C() {}` (a common singleton trick) removes the public no-arg constructor. ## Why this rule exists The language designers reasoned: if you cared enough to write a constructor, you have an opinion about how the object should be built. Silently bolting on a free no-arg constructor could let callers create half-initialized objects you never intended — violating the class's **invariants** (the rules that must always hold for an object to be valid). So writing any constructor is treated as taking full control. ## Problem 1: inheritance / super() Every constructor, as its **first action**, must call a constructor of its **superclass** (the class it `extends`). If you don't write that call, the compiler inserts `super();` — a call to the **no-arg** superclass constructor. ```java class Animal { Animal(String name) { } } // only a parameterized ctor class Dog extends Animal { Dog() { } // COMPILE ERROR: implicit super() has no matching Animal() } ``` Because `Animal` has no no-arg constructor, the implicit `super();` in `Dog()` has nothing to call. You must write `super("...")` explicitly. This is one of the most common 'why won't my subclass compile' errors. ## Problem 2: frameworks and reflection Libraries that build objects generically — JPA/Hibernate (entities), Jackson/Gson (JSON), JavaBeans, many DI containers — typically create an instance via the **no-arg constructor** and then set fields. A class with only a parameterized constructor has none, so these tools throw `InstantiationException` or similar at runtime. The remedy: explicitly declare a no-arg constructor (sometimes `protected` for JPA) alongside your parameterized one. ## The fix If you add a parameterized constructor but still need a no-arg one, just write it: ```java class Person { private String name; public Person() { } // restore the no-arg ctor public Person(String name) { this.name = name; } } ```

  • If I write only a private no-arg constructor, can outside code still do new MyClass()?
    No. A declared private constructor both suppresses the default public one and blocks external instantiation — exactly the singleton/utility-class pattern.
  • Does JPA strictly require the no-arg constructor to be public?
    It must be at least protected (public or protected). Hibernate can use reflection on a non-public one, but the JPA spec mandates public or protected.

saying these in an interview costs you the question

  • Believing only a no-arg constructor you write suppresses the default (any constructor does)
  • Forgetting that a subclass needs an accessible parent constructor for the implicit super()
  • Assuming frameworks can call your parameterized constructor automatically
  • Thinking a private constructor still leaves a usable default constructor

context