The this keyword

Every instance method secretly receives one extra variable: this, a reference to the object it was called on. You'll see why name = name silently does nothing, how this.name fixes it, how an object can pass itself to another object, how returning this makes calls chain like StringBuilder's, and why static code has no this, then practise with 10 problems.

Module 6 · OOP Basics⏱ 20 minBeginner10 practice problems
1 The story

The constructor that did nothing

Riya writes a neat constructor: Student(String name) { name = name; }. It compiles without a single warning. She creates three students, prints them, and gets null, null, null. She stares at the line for ten minutes. It looks perfectly correct.

Constructor frame (stack) this → #1name → "Riya"(the parameter) Object #1 (heap) Studentname = ?(the field) name = name; parameter → parameter: field stays null this.name = name; parameter → field of this object myphatshala.in
Riya

Sir, name = name should copy the name. Why is every student null?

Arjun Sir

Inside the constructor there are two things called name: the parameter and the field. The closer one, the parameter, wins. So you copied the parameter into itself.

Riya

Then how do I say "the field of this student"?

Arjun Sir

Exactly like that: this.name. Every method gets a hidden variable this that points to the object it is working on. this.name = name means "my field gets the parameter's value".

2 Definition

What is the this keyword?

Formal definition (write this in exams)

this is a keyword that, inside an instance method or constructor, refers to the current object: the object on which the method was invoked, or the object being constructed. It is used to access fields hidden by local variables or parameters (this.field), to call another constructor of the same class (this(...)), to pass the current object as an argument, and to return it. It cannot be used in a static context, and it cannot be assigned.

In simple words

"Me, the object you called." When Riya's object runs show(), this is Riya's object; when Kabir's runs it, this is Kabir's.

Words you'll meet in this lesson

Current objectThe object before the dot: s in s.show().
ShadowingA local variable or parameter hiding a field with the same name.
this.fieldReaches the field even when it is shadowed.
this(...)Calls another constructor of the same class (Lesson 6.2).
Fluent interfaceMethods that return this so calls can be chained.
Static contextStatic methods and blocks: no object, so no this.

Four uses of this

this.fieldField instead of a same-named parameter: this.name = name;
this(...)Constructor chaining; first statement of a constructor
method(this)Pass the current object to another object or method
return this;Return the current object so calls can be chained
Not allowedIn static methods (main too), and this = other; ("cannot assign to 'this'")

Exam tip: this (a reference to the current object) and this(...) (a call to another constructor) are different things. Both are asked as MCQs. Neither is allowed in a static method.

3 Types and ways to use it

The uses of this, side by side

this.field = param

Copies a parameter into the field with the same name. The most common use, in nearly every constructor and setter.

Shadowing fix

Pass this

new Order(this, amount): the customer hands itself to the order it creates, so the order knows who placed it.

method(this)

Return this

Each call returns the same object, so the next call can follow: order.size("L").crust("Thin").

Fluent chain

this is the object before the dot

class Box {
    void whoAmI() {
        System.out.println("this = " + this);
    }
}

public class Main {
    public static void main(String[] args) {
        Box b = new Box();
        System.out.println("b    = " + b);
        b.whoAmI();
    }
}
b = Box@15db9742 this = Box@15db9742

Both lines print the same class name and hash code, so this inside whoAmI() is exactly the object b refers to. (The number after @ differs between runs and machines, so your output will differ.)

When do you need to write this?

SituationPlain name meansNeed this.?
No parameter or local called nameThe fieldNo (optional, some teams write it for clarity)
Parameter called nameThe parameterYes, to reach the field
Local variable called nameThe local variableYes, to reach the field
Inside a static methodOnly a static field or a localNot possible: there is no this

Silent bug: name = name; compiles with no error and no warning by default. The field just keeps its default (null, 0). Many IDEs highlight it as "assignment to itself"; read those warnings.

4 Step by step

How this gets its value

  1. You call a method on an object

    riya.show();
    The JVM pushes a frame for show and puts the reference from riya into the frame's first slot. That slot is this; in bytecode it is read with aload_0.
  2. Plain field names use it automatically

    void show() {
        System.out.println(name);   // really this.name
    }
    javac compiles name as "load this, then read its field name". That's how the same method code prints Riya's name for Riya and Kabir's for Kabir.
  3. A parameter with the same name hides the field

    void rename(String name) {
        this.name = name;   // field = parameter
    }
    Java looks for a name in the closest scope first: local variables and parameters, then fields. this. skips straight to the field.
  4. Pass or return the current object

    Order placeOrder(int amt) { return new Order(this, amt); }
    Wallet add(int amt)       { balance += amt; return this; }
    Passing or returning this copies a reference, as always: no new object is created. The Order stores a reference to the same customer; the chained call works on the same wallet.
  5. No this in static code

    public static void main(String[] args) {
        this.visits++;   // compile error
    }
    Static methods are called on the class, not on an object, so their frame has no slot 0 reference to fill. javac reports: non-static variable this cannot be referenced from a static context.
5 See it happen

The hidden this: both views

Left: the code and its result. Right: the method frame with its hidden this, and the object it points to.

Following this 6 steps
What you see Student s = new Student("Riya"); Student(String name) { name = name; } Student(String name) { this.name = name; } s.show(); // println(this.name) s.marks(80).city("Pune"); static void test() { this.name = "X"; } // constructor starts for #1 s.name → null (!) s.name → Riya Riya marks 80, city Pune each call returned s itself error: non-static variable this cannot be referenced from a static context Two things named name: parameter and field. Compiles, runs, and stores nothing. this.name reaches the field. Fixed. this is the object before the dot. return this lets calls chain. Static code has no current object. myphatshala.in
Behind the screen Stack Heap Student(String name) show() marks(int m) / city(…) static test() this → #1 this: none! name → "Riya" m = 80 main s: not set yet s → #1 #1 Student name = null name = "Riya" marks = 0 marks = 80 city = null city = "Pune" returns #1 this → the object under construction. The arrow loops back: parameter to parameter. this.name writes into #1's field. Slot 0 of every instance frame holds this. return this hands back #1 for the next call. A static frame has no slot for this. myphatshala.in
6 Real-world use

this in real systems

You'll see this in almost every Java class you read at work, mostly in constructors and setters, and in the fluent APIs of popular libraries.

Watch it with an example: a fluent order builder

Methods that end with return this; can be chained. Watch three calls work on the same object, because this is always “the object this method was called on”.

order.add("Tea").add("Vada").note("less sugar") 5 steps
Animated example new Order().add("Tea").add("Vada").note("less sugar"); #1 Order items = [ ] items = [Tea] items = [Tea, Vada] note = "less sugar" this → #1 add("Tea") returns this add("Vada") returns this note(…) returns this → the next call is on #1 again 1 object, 3 calls, 0 temporary variables myphatshala.in
this.pan = pan;this.name = name;this.dob = dob;

1. Constructors and setters everywhere

Teams name parameters after the fields they fill (pan, name, dob) because it reads clearly, and use this. to store them. IDEs generate exactly this code.

Form data→this.field = field→Filled object

2. Fluent builders

StringBuilder.append returns this, which is why sb.append(a).append(b) works (Lesson 4.6). HTTP clients and report builders use the same style: request.header(…).timeout(…).send().

Settings→return this;→Readable chains

3. Objects that register themselves

A customer creates an order and passes this so the order knows its customer; a screen registers itself as the listener for a button: button.addListener(this).

Customer→new Order(this, amt)→Linked records
this == other ?

4. Comparing with another object

Methods that work on two objects of the same class use this for one and a parameter for the other: a.transferTo(b, 500) checks if (other == this) to block a transfer to the same account.

Two accounts→this vs other→Safe transfer

Examples are simplified. Library method names above are typical patterns, not the exact API of any one product.

7 Run the code

A fluent pizza order

class PizzaOrder {
    String size = "Medium";
    String crust = "Classic";
    int extraCheese;

    PizzaOrder size(String size) {
        this.size = size;
        return this;              // hand back the same object
    }

    PizzaOrder crust(String crust) {
        this.crust = crust;
        return this;
    }

    PizzaOrder addCheese() {
        this.extraCheese++;
        return this;
    }

    void print() {
        System.out.println(size + ", " + crust + " crust, extra cheese x" + extraCheese);
    }
}

public class Main {
    public static void main(String[] args) {
        PizzaOrder order = new PizzaOrder();
        order.size("Large").crust("Thin").addCheese().addCheese().print();
        System.out.println(order.size("Small") == order);
    }
}
Large, Thin crust, extra cheese x2 true
  • this.size = size;Field on the left, parameter on the right.
  • return this;Returns the order the method was called on, so the next call can follow.
  • this.extraCheese++;this. is optional here (no clash), but harmless.
  • order.size("Small") == ordertrue: the method returned the very same object, not a copy.
8 Line by line

Chaining on one wallet

Watch this appear in every add frame, always pointing to #1, and the returned reference feeding the next call.

Worked examples: real problems, solved and traced in memory

Three business problems where this does the real work. Run each solution, then step through it: in every method frame, look at the this variable and follow it to the object on the heap.

Example 1HR · appraisal

Raise and promote in one chain

Problem statement

During appraisal, HR gives Sneha a 10% raise and promotes her to "Senior Developer" in one readable statement. Write raise(percent) and promote(title) so they can be chained.

Input
new Employee("Sneha", "Developer", 40000)
.raise(10).promote("Senior Developer")
Expected output
Sneha | Senior Developer | Rs 44000

Approach

  1. The constructor uses this.field = parameter because the parameters have the same names as the fields.
  2. raise updates this.salary and returns this.
  3. promote is called on the returned reference, which is the same employee, and also returns this.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Healthcare · appointments

A doctor books an appointment for a patient

Problem statement

In a clinic app, a doctor books a patient with doctor.book(patient, slot). The new Appointment must hold references to both the doctor and the patient. Print the appointment slip.

Input
Doctor "Dr. Mehta" (Cardiology)
Patient "Asha", slot "10:30"
Expected output
10:30 | Asha with Dr. Mehta (Cardiology)

Approach

  1. book runs on a Doctor object, so inside it this is that doctor.
  2. It creates new Appointment(this, patient, slot): the doctor passes itself along with the patient.
  3. The appointment stores two references; nothing is copied.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Retail · price comparison

Find the cheapest seller

Problem statement

Three sellers offer the same phone at different prices. Write cheaperOf(Product other) that returns whichever of this and other is cheaper, and use it in a chain to find the cheapest of the three.

Input
("Seller A", 15999), ("Seller B", 15499), ("Seller C", 15749)
Expected output
Buy from Seller B at Rs 15499

Approach

  1. Inside cheaperOf, two products take part: this (before the dot) and other (the argument).
  2. Return the reference of the cheaper one: either this or other. No new object is created.
  3. Chain it: a.cheaperOf(b).cheaperOf(c). The second call runs on whichever product won the first.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 6.3 in one screen

  • this = reference to the current object (the one before the dot, or the one being constructed).
  • Every instance method and constructor has it as a hidden first variable (aload_0).
  • A parameter or local with a field's name shadows it: use this.field.
  • name = name; compiles but does nothing useful.
  • this(...) calls another constructor: first statement only.
  • Pass this to link objects; return this; for fluent chains.
  • No this in static methods; this can't be reassigned.

Interview and viva questions

What is the this keyword in Java?

A reference to the current object inside an instance method or constructor. It is used to access shadowed fields, call another constructor with this(...), pass the current object to other methods, and return the current object for method chaining.

Why can't we use this inside a static method?

A static method belongs to the class and is called without any object, so there is no current object for this to refer to. The compiler reports "non-static variable this cannot be referenced from a static context".

Is this a variable? Can we change it?

It behaves like a final local variable that the JVM fills in (slot 0 of the frame). You can read it, pass it and return it, but this = other; is a compile error ("cannot assign to 'this'").

What is the difference between this and this()?

this is a reference to the current object and can be used anywhere in instance code. this(...) is a call to another constructor of the same class and is allowed only as the first statement of a constructor.

Why do setters often return this?

So that several setters can be called in one chained expression, which reads like a sentence and is common in builders. Plain JavaBean setters, which some frameworks expect, return void instead, so teams pick one style per class.

Practice problems

Practise the four uses of this: reaching shadowed fields, chaining constructors, passing the current object and returning it. The last three are real business tasks.

P1Easy

Fix the shadowing bug

This Employee constructor stores nothing: every field stays at its default. Fix it using this and print the employee.

Input
new Employee("Sneha", "E102", 42000)
Expected output
E102 | Sneha | Rs 42000
Show solution and explanation
class Employee {
    String name;
    String id;
    int salary;

    Employee(String name, String id, int salary) {
        this.name = name;          // was: name = name;
        this.id = id;              // was: id = id;
        this.salary = salary;      // was: salary = salary;
    }
}

public class Main {
    public static void main(String[] args) {
        Employee e = new Employee("Sneha", "E102", 42000);
        System.out.println(e.id + " | " + e.name + " | Rs " + e.salary);
    }
}
E102 | Sneha | Rs 42000

How it works: each parameter has the same name as a field, so a plain name means the parameter. this.name means "the name field of the object being built". Without the fix the output would be null | null | Rs 0.

P2Easy

A setter with a guard

Write setAge(int age) for a Person. It should store the age only if it is between 0 and 120, otherwise print a message and keep the old age.

Input
setAge(25), then setAge(-4)
Expected output
Invalid age -4 for Kabir
Kabir is 25
Show solution and explanation
class Person {
    String name;
    int age;

    Person(String name) {
        this.name = name;
    }

    void setAge(int age) {
        if (age < 0 || age > 120) {
            System.out.println("Invalid age " + age + " for " + name);
            return;
        }
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person("Kabir");
        p.setAge(25);
        p.setAge(-4);
        System.out.println(p.name + " is " + p.age);
    }
}
Invalid age -4 for Kabir Kabir is 25

How it works: inside setAge, age is the new value (parameter) and this.age is the stored one (field). We check the parameter first, and only then copy it into the field.

P3Easy

Chain a counter

Make a Score class whose add(int points) returns this. Add 4, 6 and 2 points in one chained statement and print the total.

Input
s.add(4).add(6).add(2)
Expected output
Total: 12
Show solution and explanation
class Score {
    int total;

    Score add(int points) {
        total += points;
        return this;
    }
}

public class Main {
    public static void main(String[] args) {
        Score s = new Score();
        s.add(4).add(6).add(2);
        System.out.println("Total: " + s.total);
    }
}
Total: 12

How it works: s.add(4) returns the same Score object, so .add(6) is called on it, and so on. Only one object exists the whole time.

P4Medium

Compare with another object

Add a method isOlderThan(Person other) that compares this person's age with another person's age. Use it for two people.

Input
Riya 21, Arjun 45
Expected output
Riya older than Arjun? false
Arjun older than Riya? true
Show solution and explanation
class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    boolean isOlderThan(Person other) {
        return this.age > other.age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person riya = new Person("Riya", 21);
        Person arjun = new Person("Arjun", 45);
        System.out.println("Riya older than Arjun? " + riya.isOlderThan(arjun));
        System.out.println("Arjun older than Riya? " + arjun.isOlderThan(riya));
    }
}
Riya older than Arjun? false Arjun older than Riya? true

How it works: two Person objects take part: this is the one before the dot, other is the argument. Writing this.age here isn't required, but it makes the comparison read clearly.

P5Medium

Pass this to link objects

A Teacher can create a Batch with startBatch(name). The batch must remember its teacher. Create two batches from one teacher and print each batch with its teacher's name.

Input
Teacher "Arjun Sir" starts "Java-Morning" and "Java-Evening"
Expected output
Java-Morning by Arjun Sir
Java-Evening by Arjun Sir
Same teacher object: true
Show solution and explanation
class Teacher {
    String name;

    Teacher(String name) {
        this.name = name;
    }

    Batch startBatch(String batchName) {
        return new Batch(batchName, this);
    }
}

class Batch {
    String name;
    Teacher teacher;

    Batch(String name, Teacher teacher) {
        this.name = name;
        this.teacher = teacher;
    }
}

public class Main {
    public static void main(String[] args) {
        Teacher t = new Teacher("Arjun Sir");
        Batch b1 = t.startBatch("Java-Morning");
        Batch b2 = t.startBatch("Java-Evening");
        System.out.println(b1.name + " by " + b1.teacher.name);
        System.out.println(b2.name + " by " + b2.teacher.name);
        System.out.println("Same teacher object: " + (b1.teacher == b2.teacher));
    }
}
Java-Morning by Arjun Sir Java-Evening by Arjun Sir Same teacher object: true

How it works: inside startBatch, this is the teacher it was called on. Passing it to the Batch constructor stores a reference, so both batches point to the same Teacher object, not to copies.

P6Medium

Constructor chaining with this(...)

A Shirt can be created with (size), (size, colour) or (size, colour, price). Defaults: colour "White", price Rs 799. Use this(...) so only one constructor assigns fields.

Input
new Shirt("M"), new Shirt("L", "Blue"), new Shirt("XL", "Black", 999)
Expected output
M | White | Rs 799
L | Blue | Rs 799
XL | Black | Rs 999
Show solution and explanation
class Shirt {
    String size;
    String colour;
    int price;

    Shirt(String size) {
        this(size, "White");
    }

    Shirt(String size, String colour) {
        this(size, colour, 799);
    }

    Shirt(String size, String colour, int price) {
        this.size = size;
        this.colour = colour;
        this.price = price;
    }

    void show() {
        System.out.println(size + " | " + colour + " | Rs " + price);
    }
}

public class Main {
    public static void main(String[] args) {
        new Shirt("M").show();
        new Shirt("L", "Blue").show();
        new Shirt("XL", "Black", 999).show();
    }
}
M | White | Rs 799 L | Blue | Rs 799 XL | Black | Rs 999

How it works: this(...) (with brackets) calls another constructor, while this.size (with a dot) reaches a field. Both appear here: the short constructors chain, the full one assigns.

P7Medium

A fluent message builder

Build an SMS text with a fluent Message class: to(name), line(text) and sign(sender) each return this; text() returns the final String.

Input
to("Riya").line("Your order is out for delivery.").line("OTP: 4821").sign("QuickKart")
Expected output
Hi Riya,
Your order is out for delivery.
OTP: 4821
- QuickKart
Show solution and explanation
class Message {
    StringBuilder body = new StringBuilder();

    Message to(String name) {
        body.append("Hi ").append(name).append(",\n");
        return this;
    }

    Message line(String text) {
        body.append(text).append("\n");
        return this;
    }

    Message sign(String sender) {
        body.append("- ").append(sender);
        return this;
    }

    String text() {
        return body.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        String sms = new Message()
                .to("Riya")
                .line("Your order is out for delivery.")
                .line("OTP: 4821")
                .sign("QuickKart")
                .text();
        System.out.println(sms);
    }
}
Hi Riya, Your order is out for delivery. OTP: 4821 - QuickKart

How it works: each method appends to the same StringBuilder field and returns this, so the calls read top to bottom like the message itself. text() ends the chain by returning a String instead of the builder. "QuickKart" is a made-up shop name.

P8Business problem

Fund transfer between accounts

Write transferTo(Account other, int amount). It must refuse a transfer to the same account (other == this) and refuse if the balance is too low; otherwise move the money. Try a normal transfer, a self-transfer and an oversized one.

Input
Riya Rs 5000, Kabir Rs 1000
riya → kabir 1500; riya → riya 100; kabir → riya 9000
Expected output
Done: Rs 1500 from Riya to Kabir
Rejected: Riya cannot transfer to the same account
Rejected: Kabir has only Rs 2500
Riya: Rs 3500, Kabir: Rs 2500
Show solution and explanation
class Account {
    String holder;
    int balance;

    Account(String holder, int balance) {
        this.holder = holder;
        this.balance = balance;
    }

    boolean transferTo(Account other, int amount) {
        if (other == this) {
            System.out.println("Rejected: " + holder + " cannot transfer to the same account");
            return false;
        }
        if (amount > this.balance) {
            System.out.println("Rejected: " + holder + " has only Rs " + balance);
            return false;
        }
        this.balance -= amount;
        other.balance += amount;
        System.out.println("Done: Rs " + amount + " from " + holder + " to " + other.holder);
        return true;
    }
}

public class Main {
    public static void main(String[] args) {
        Account riya = new Account("Riya", 5000);
        Account kabir = new Account("Kabir", 1000);
        riya.transferTo(kabir, 1500);
        riya.transferTo(riya, 100);
        kabir.transferTo(riya, 9000);
        System.out.println("Riya: Rs " + riya.balance + ", Kabir: Rs " + kabir.balance);
    }
}
Done: Rs 1500 from Riya to Kabir Rejected: Riya cannot transfer to the same account Rejected: Kabir has only Rs 2500 Riya: Rs 3500, Kabir: Rs 2500

How it works:

  1. this is the sending account, other the receiving one. Using both names makes the money flow obvious.
  2. other == this compares references: true only when both are literally the same object.
  3. Real banks also log every transfer and do the two updates inside one database transaction so money is never lost halfway.
P9Business problem

Shopping cart with chained adds

A Cart supports add(item, price, qty) returning this, and applyCoupon(percent) also returning this. Build a cart in one chain and print the payable amount.

Input
add("Saree", 2499, 1), add("Bangles", 349, 2), applyCoupon(10)
Expected output
Added 1 x Saree
Added 2 x Bangles
3 items, subtotal Rs 3197
Payable after 10% coupon: Rs 2878
Show solution and explanation
class Cart {
    int items;
    int subtotal;
    int discountPercent;

    Cart add(String item, int price, int qty) {
        this.items += qty;
        this.subtotal += price * qty;
        System.out.println("Added " + qty + " x " + item);
        return this;
    }

    Cart applyCoupon(int percent) {
        this.discountPercent = percent;
        return this;
    }

    int payable() {
        return subtotal - subtotal * discountPercent / 100;
    }
}

public class Main {
    public static void main(String[] args) {
        Cart cart = new Cart()
                .add("Saree", 2499, 1)
                .add("Bangles", 349, 2)
                .applyCoupon(10);
        System.out.println(cart.items + " items, subtotal Rs " + cart.subtotal);
        System.out.println("Payable after 10% coupon: Rs " + cart.payable());
    }
}
Added 1 x Saree Added 2 x Bangles 3 items, subtotal Rs 3197 Payable after 10% coupon: Rs 2878

How it works:

  1. new Cart() creates one object; each chained call returns it, so the final cart variable refers to that same object.
  2. Subtotal: 2499 + 2 × 349 = 3197. Integer arithmetic: 3197 × 10 / 100 = 319, so payable is 2878.
  3. Real carts usually use paise (long) or BigDecimal to avoid rounding surprises with money.
P10Business problem

Ride assignment: the driver passes itself

When a Driver accepts a Ride, the driver calls ride.assign(this) and becomes busy. A busy driver can't accept another ride. Simulate one driver and two ride requests.

Input
Driver "Manoj" (MH12 AB 4321)
Ride 1: Kothrud → Hinjewadi, Ride 2: Baner → Wakad
Expected output
Manoj accepted Kothrud -> Hinjewadi
Manoj is busy, cannot take Baner -> Wakad
Kothrud -> Hinjewadi: Manoj (MH12 AB 4321)
Baner -> Wakad: searching...
Show solution and explanation
class Ride {
    String route;
    Driver driver;

    Ride(String route) {
        this.route = route;
    }

    void assign(Driver driver) {
        this.driver = driver;
    }
}

class Driver {
    String name;
    String vehicle;
    boolean busy;

    Driver(String name, String vehicle) {
        this.name = name;
        this.vehicle = vehicle;
    }

    boolean accept(Ride ride) {
        if (busy) {
            System.out.println(name + " is busy, cannot take " + ride.route);
            return false;
        }
        ride.assign(this);
        busy = true;
        System.out.println(name + " accepted " + ride.route);
        return true;
    }
}

public class Main {
    public static void main(String[] args) {
        Driver manoj = new Driver("Manoj", "MH12 AB 4321");
        Ride r1 = new Ride("Kothrud -> Hinjewadi");
        Ride r2 = new Ride("Baner -> Wakad");
        manoj.accept(r1);
        manoj.accept(r2);
        System.out.println(r1.route + ": " + r1.driver.name + " (" + r1.driver.vehicle + ")");
        System.out.println(r2.route + ": " + (r2.driver == null ? "searching..." : r2.driver.name));
    }
}
Manoj accepted Kothrud -> Hinjewadi Manoj is busy, cannot take Baner -> Wakad Kothrud -> Hinjewadi: Manoj (MH12 AB 4321) Baner -> Wakad: searching...

How it works:

  1. Inside accept, this is Manoj's Driver object. ride.assign(this) stores a reference to him in the ride.
  2. The second ride is refused because busy is now true, so r2.driver stays null; we check for null before reading its name.
  3. Real apps also handle the race where two riders request the same driver at the same moment (Module 12).

Real-world scenario questions (asked in company interviews)

These look like small mistakes, but each one has reached production somewhere. Decide your answer first, then open the model answer.

Insurance · data bugFresher

Every policy has a null nominee

After a refactor, every new insurance policy is saved with a null nominee, though the screen clearly sends one. The constructor has the line nominee = nominee;. Tests pass and there is no exception. Explain and fix.

The interviewer is checking: do you recognise field shadowing?

Show a strong answer
  • The parameter is named nominee, the same as the field, so inside the constructor nominee means the parameter. The line assigns the parameter to itself; the field keeps its default null.
  • Fix: this.nominee = nominee;
  • Add a test that creates a policy and checks the nominee, and turn on the IDE or static-analysis warning for self-assignment so it can't come back silently.

Avoid: renaming the parameter to n to dodge the issue. Clear names plus this. is the standard.

Edtech · utility codeFresher

“Just make main use the field”

A junior wants main to update a field attemptCount of the QuizApp class and writes this.attemptCount++. It doesn't compile, so they plan to make the field static. What would you advise?

The interviewer is checking: do you understand static context versus objects, and the cost of making things static?

Show a strong answer
  • main is static, so there is no current object and no this.
  • Create the object and use it: QuizApp app = new QuizApp(); app.attemptCount++; or better, move the logic into an instance method like app.run().
  • Making the field static would share one count across every quiz object (Lesson 6.4), which is wrong as soon as two quizzes exist.

Avoid: making fields static just to silence a compile error.

Fintech · payments1–3 years

A transfer to the same account doubled the balance

Account.transferTo(Account other, long amount) reads both balances into locals, subtracts from one, adds to the other, then writes both back. When a user transfers money to their own account, the balance increases. Why, and how do you guard against it?

The interviewer is checking: can you reason about this and a parameter referring to the same object?

Show a strong answer
  • When other == this, both references point to one object. The method reads the balance twice, writes "balance − amount", then overwrites it with "balance + amount", so the final value is higher.
  • Guard at the start: if (other == this) throw new IllegalArgumentException("Same account"); (or reject it in validation before calling).
  • Update fields directly (this.balance -= amount; other.balance += amount;) instead of stale local copies, and wrap real transfers in a database transaction.

Avoid: assuming two parameters (or this and a parameter) always refer to different objects.

SaaS · API design1–3 years

A chained call that crashes only sometimes

A report builder is used as new Report().title(t).filter(f).build(). Production logs show a NullPointerException "because the return value of Report.filter(...) is null" for some customers. What do you look for?

The interviewer is checking: do you know how fluent methods must be written?

Show a strong answer
  • The message says filter returned null. Look for a path inside it, often an early return null; when the filter is empty, that doesn't return this.
  • Every fluent method must end every path with return this;; handle "nothing to do" by skipping the work, not by returning null.
  • Add tests for each method with edge inputs (empty filter, null title) and chain them.

Avoid: adding null checks at every call site. Fix the method's contract.