Classes, objects and constructors
Fields, methods, this, constructor overloading and chaining, static against instance, and the order in which initialisation actually happens.
A class is a template; an object is one thing built from it. Everything else in this lesson is detail about when memory is allocated and when code runs.
A class
public class Student {
// fields — the state of one object
private String name;
private String roll;
private int marks;
// constructor — runs when an object is created
public Student(String name, String roll) {
this.name = name;
this.roll = roll;
this.marks = 0;
}
// methods — the behaviour
public String label() {
return roll + " — " + name;
}
public void record(int score) {
if (score < 0 || score > 100) {
throw new IllegalArgumentException("marks out of range: " + score);
}
this.marks = score;
}
public int getMarks() {
return marks;
}
}Student s = new Student("Raja", "21B81A05H4");
s.record(87);
System.out.println(s.label() + " scored " + s.getMarks());What new actually does
Four steps, and knowing them in order answers several questions at once:
- Allocate memory on the heap for the object's fields.
- Initialise fields to defaults —
0,false,null. - Run field initialisers and instance initialiser blocks, top to bottom.
- Run the constructor body.
Then new evaluates to a reference to that object, which is what gets stored in s. The
object is on the heap; s is a reference on the stack.
Student a = new Student("Raja", "05H4");
Student b = a; // second reference, same object
b.record(90);
System.out.println(a.getMarks()); // 90 — one object
Student c = new Student("Raja", "05H4");
System.out.println(a == c); // false — different objectsSame as everywhere else: == compares references. Lesson 11 covers making equals mean what you
want.
this
this is a reference to the current object. Two real uses:
Disambiguating a shadowed field, which is why constructors are full of it:
public Student(String name) {
this.name = name; // field = parameter; without `this` you assign the parameter to itself
}Calling another constructor in the same class, which must be the first statement:
public class Student {
private String name;
private String roll;
private int marks;
public Student(String name, String roll, int marks) { // the real one
this.name = name;
this.roll = roll;
this.marks = marks;
}
public Student(String name, String roll) {
this(name, roll, 0); // constructor chaining
}
public Student() {
this("unknown", "-");
}
}This is constructor chaining, and it is how you avoid duplicating validation across three
constructors. this(...) must be the first statement, and you cannot use both this(...) and
super(...) in one constructor — the parent is reached through the chain.
Constructor rules
- Same name as the class, no return type.
- If you write no constructor, the compiler supplies a no-argument default constructor that does nothing.
- If you write any constructor, that default disappears. So adding a two-argument constructor
can break
new Student()elsewhere in the codebase — a genuine and commonly-asked consequence. - Constructors can be overloaded, and can be
private(used by the singleton and builder patterns). - Constructors are not inherited.
class A {
A(int x) { }
}
class B extends A {
// compile error: no A() to call implicitly
}Because a subclass constructor implicitly calls super() — the parent's no-argument
constructor — and A no longer has one. Fix it by calling the right one explicitly:
class B extends A {
B() { super(5); }
}static
A static member belongs to the class, not to any object. One copy, shared:
public class Student {
private static int count = 0; // one, shared
private static final String COLLEGE = "MLRIT"; // constant
private String name; // one per object
public Student(String name) {
this.name = name;
count++; // every object increments the same counter
}
public static int getCount() { // callable without an object
return count;
}
}new Student("Raja");
new Student("Anu");
System.out.println(Student.getCount()); // 2 — called on the CLASSRules that get asked directly:
- A static method cannot use
thisor touch instance fields — there is no instance. - An instance method can use static fields freely.
- A static method cannot be overridden. It can be hidden by a static method with the same signature in a subclass, and which one runs is decided by the reference type at compile time, not by the object. This is why you should call static methods on the class name.
static finalin capitals is the Java convention for a constant.
public class Util {
public static int square(int x) {
return x * x; // no instance state needed — correctly static
}
}main is static for exactly this reason: it must run before any object exists.
Initialisation order
This is a favourite "what does this print?" question. The order is fixed:
public class Demo {
static int s = trace("1. static field");
static { trace("2. static block"); }
int i = trace("4. instance field");
{ trace("5. instance block"); }
Demo() { trace("6. constructor"); }
static int trace(String msg) {
System.out.println(msg);
return 0;
}
public static void main(String[] args) {
trace("3. main starts");
new Demo();
new Demo();
}
}Output:
1. static field
2. static block
3. main starts
4. instance field
5. instance block
6. constructor
4. instance field
5. instance block
6. constructorTwo things to say about it. Static members initialise once, when the class is first loaded —
before main. Instance members initialise on every new, in source order, before the
constructor body. With inheritance, the parent's chain completes before the child's begins.
Method overloading
Same name, different parameter list. Resolved at compile time by the argument types:
public class Printer {
void show(int x) { System.out.println("int"); }
void show(double x) { System.out.println("double"); }
void show(String x) { System.out.println("String"); }
void show(int x, int y) { System.out.println("two ints"); }
void show(int... xs) { System.out.println("varargs"); }
}Printer p = new Printer();
p.show(5); // int
p.show(5.0); // double
p.show('a'); // int ← char widens to int; there is no show(char)
p.show(5, 6); // two ints
p.show(1, 2, 3); // varargs
p.show(); // varargs — an empty arrayp.show('a') printing "int" is the classic trick question. When there is no exact match, Java
prefers widening (char → int) over boxing (char → Character) over varargs, in
that order.
The return type is not part of the signature. Two methods differing only in return type will not compile.
Getters, setters and why
private int marks; // nobody outside can touch it
public int getMarks() { return marks; }
public void setMarks(int marks) {
if (marks < 0 || marks > 100) {
throw new IllegalArgumentException("out of range");
}
this.marks = marks;
}The field is private, so every write goes through one place where the rule lives. That is encapsulation with a purpose, rather than boilerplate — and if a setter has no validation and no prospect of any, a plain public field would have been honest.
Since Java 16, a class that only carries data can be a record, which writes the constructor,
accessors, equals, hashCode and toString for you:
public record Point(int x, int y) { }
Point p = new Point(3, 4);
System.out.println(p.x()); // 3 — accessor is x(), not getX()
System.out.println(p); // Point[x=3, y=4]
System.out.println(p.equals(new Point(3, 4))); // trueRecords are implicitly final and their fields are immutable.
What to take into an interview
newallocates, defaults the fields, runs field initialisers and blocks, then the constructor.- The object lives on the heap; the reference lives on the stack.
this.x = xdisambiguates;this(...)chains constructors and must be the first statement.- Writing any constructor removes the compiler's default no-argument one.
- Constructors are not inherited, and a subclass constructor implicitly calls
super(). staticbelongs to the class: one copy, nothis, cannot be overridden (only hidden).- Static initialisers run once at class load, before
main; instance ones run on everynew. - Overloading resolves at compile time, preferring widening, then boxing, then varargs.
- Return type is not part of the signature.