Fundamentals 12 min read

Understanding Java Classes and Inheritance: Initialization, Constructors, and Common Interview Questions

This article explains Java class fundamentals, including file naming rules, default member initialization, static loading order, inheritance mechanics, constructor behavior, super usage, and provides typical interview code examples with detailed output analysis.

Java Captain
Java Captain
Java Captain
Understanding Java Classes and Inheritance: Initialization, Constructors, and Common Interview Questions

For object‑oriented programming languages, classes are the essential building block, enabling abstraction, encapsulation, inheritance, and polymorphism.

In Java, a source file must end with .java ; if it contains a public class, the file name must match that class, otherwise any name (except starting with a digit) is allowed.

Member variables receive default values when not explicitly initialized: numeric primitives (char, short, byte, int, long, float, double) become 0 , boolean becomes false , and reference types become null .

If no constructor is declared, the compiler generates a no‑argument constructor; however, once any constructor is defined, the compiler no longer adds one automatically. All constructors are instance members, not static.

When an object is created, the JVM first checks whether the class has been loaded. If not, it loads the class, initializing static fields and executing static blocks in the order they appear. Class loading occurs only once and on demand.

Example of static‑block execution:

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Bread bread1 = new Bread();
        Bread bread2 = new Bread();
    }
}
class Bread {
    static {
        System.out.println("Bread is loaded");
    }
    public Bread() {
        System.out.println("bread");
    }
}

Running this prints "Bread is loaded" only once, demonstrating that static initialization happens a single time.

During object creation, instance fields are initialized first, then the constructor runs. The following code shows the order of initialization between nested objects:

public class Test {
    public static void main(String[] args)  {
        new Meal();
    }
}
class Meal {
    public Meal() {
        System.out.println("meal");
    }
    Bread bread = new Bread();
}
class Bread {
    public Bread() {
        System.out.println("bread");
    }
}

Output:

bread
meal

Inheritance in Java is expressed with the extends keyword; every class implicitly extends Object if no explicit superclass is given. Java permits only single inheritance, though a class may have many subclasses.

Subclass inheritance rules for fields:

Public and protected members are inherited; private members are not.

Package‑private members are inherited only when the subclass resides in the same package.

If a subclass declares a field with the same name, it hides the superclass field; the hidden field can be accessed with super.fieldName .

Method inheritance follows similar rules: public and protected methods are inherited, private methods are not, and package‑private methods are inherited only within the same package. A subclass can override an inherited method by providing a method with the same signature; the overridden method can be invoked via super.methodName() . Hiding applies to static methods, while overriding applies to instance methods.

Constructors are not inherited. If a superclass only provides parameterized constructors, the subclass must explicitly invoke one of them with super(args) as the first statement in its constructor. If a no‑argument constructor exists, the compiler inserts an implicit super() call when the subclass constructor does not specify one.

class Shape {
    protected String name;
    public Shape(){
        name = "shape";
    }
    public Shape(String name) {
        this.name = name;
    }
}
class Circle extends Shape {
    private double radius;
    public Circle() {
        radius = 0;
    }
    public Circle(double radius) {
        this.radius = radius;
    }
    public Circle(double radius,String name) {
        this.radius = radius;
        this.name = name;
    }
}

The super keyword is used either to access a superclass field or method ( super.field , super.method() ) or to invoke a superclass constructor ( super(arg1, arg2) ), which must be the first statement in the subclass constructor.

Interview question 1 demonstrates constructor and initialization order:

public class Test {
    public static void main(String[] args)  {
        new Circle();
    }
}
class Draw {
    public Draw(String type) {
        System.out.println(type+" draw constructor");
    }
}
class Shape {
    private Draw draw = new Draw("shape");
    public Shape(){
        System.out.println("shape constructor");
    }
}
class Circle extends Shape {
    private Draw draw = new Draw("circle");
    public Circle() {
        System.out.println("circle constructor");
    }
}

Output:

shape draw constructor
shape constructor
circle draw constructor
circle constructor

The output reflects that static and instance fields of the superclass are initialized before its constructor runs, followed by the subclass’s fields and constructor.

Interview question 2 explores hiding versus overriding:

public class Test {
    public static void main(String[] args)  {
        Shape shape = new Circle();
        System.out.println(shape.name);
        shape.printType();
        shape.printName();
    }
}
class Shape {
    public String name = "shape";
    public Shape(){
        System.out.println("shape constructor");
    }
    public void printType() {
        System.out.println("this is shape");
    }
    public static void printName() {
        System.out.println("shape");
    }
}
class Circle extends Shape {
    public String name = "circle";
    public Circle() {
        System.out.println("circle constructor");
    }
    public void printType() {
        System.out.println("this is circle");
    }
    public static void printName() {
        System.out.println("circle");
    }
}

Output:

shape constructor
circle constructor
shape
this is circle
circle

This shows that instance fields are hidden (the reference type Shape accesses shape.name ), while instance methods are overridden (dynamic dispatch calls Circle.printType() ), and static methods are hidden (the call to printName() resolves to Shape.printName() because it is invoked on the reference type).

JavaInterviewoopClassesInitializationInheritanceConstructors
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.