The this Keyword

IB Syllabus: B3.1: Use the this keyword to refer to the current object.


Key Concepts

What is this?

The this keyword is a reference to the current object: the specific instance whose method or constructor is currently executing. Every non-static method and constructor has an invisible this reference that points to the object the code is running on. (Python’s twin of this is self, but it is not invisible: self must be written as the first parameter of every method.)

You use this most often to resolve name conflicts between method parameters and instance variables.

The Parameter Shadowing Problem

When a constructor or method parameter has the same name as an instance variable, the parameter shadows (hides) the instance variable. Without this, the compiler uses the closest scope (the parameter) for both sides of the assignment.

public class Pet {
    private String name;

    public Pet(String name) {
        name = name;  // BUG: assigns the parameter to itself
                      // the instance variable stays null
    }

    public String getName() { return name; }
}
class Pet():
    def __init__(self, name):
        name = name   # BUG: assigns the parameter to itself
                      # the attribute self._name is never created

    def get_name(self):
        return self._name
Pet p = new Pet("Max");
System.out.println(p.getName());  // null -- the instance variable was never set!
p = Pet("Max")
print(p.get_name())   # error - the attribute was never created
                      # (Java gives null here; Python raises an AttributeError)

The line name = name assigns the parameter name to itself. The instance variable this.name is never touched and remains null.

The Fix: this.variable

Using this.name explicitly refers to the instance variable, while the bare name refers to the parameter:

public class Pet {
    private String name;

    public Pet(String name) {
        this.name = name;  // this.name = instance variable
                           // name = parameter
    }

    public String getName() { return name; }
}
class Pet():
    def __init__(self, name):
        self._name = name   # self._name = the object's attribute
                            # name = the parameter

    def get_name(self):
        return self._name
Pet p = new Pet("Max");
System.out.println(p.getName());  // Max -- works correctly
p = Pet("Max")
print(p.get_name())   # Max - works correctly

this.name always refers to the instance variable. Plain name refers to the closest scope: inside a constructor or method with a name parameter, that means the parameter. Outside such a context, plain name and this.name are identical.

When this is Required

this is required when a parameter name matches an instance variable name. Without it, the assignment does nothing useful.

public void setAge(int age) {
    this.age = age;  // required -- parameter shadows instance variable
}
def set_age(self, age):
    self._age = age   # self. is ALWAYS required in Python - the attribute
                      # and the parameter never clash

When this is Optional

If there is no name conflict, this is optional. Both versions below are equivalent:

public double getArea() {
    return this.width * this.height;  // explicit -- works
}

public double getArea() {
    return width * height;            // implicit -- also works (no shadowing)
}
def get_area(self):
    return self._width * self._height   # Python has no "implicit" form -
                                        # attributes are always reached through self

Many programmers use this consistently even when optional, for clarity. Others only use it when needed. Both styles are accepted. (In Python, self is never optional: there is only one style.)

Using this in Setters

Setters almost always have a parameter with the same name as the attribute they modify:

public class Circle {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;  // no conflict, this is optional
    }

    public void setRadius(double radius) {
        if (radius > 0) {
            this.radius = radius;  // required -- parameter shadows field
        }
    }

    public double getArea() {
        return Math.PI * radius * radius;
    }
}
import math

class Circle():
    def __init__(self, radius):
        self._radius = radius

    def get_radius(self):
        return self._radius

    def set_radius(self, radius):
        if radius > 0:
            self._radius = radius   # self. keeps the attribute and the parameter apart

    def get_area(self):
        return math.pi * self._radius * self._radius

Avoiding the Problem Entirely

Some programmers avoid shadowing by giving parameters different names:

public Pet(String petName) {
    name = petName;  // no conflict, no this needed
}
def __init__(self, pet_name):
    self._name = pet_name   # a different parameter name works in Python too,
                            # but self. is still required either way

This works, but the IB convention and most Java style guides prefer matching names with this:

public Pet(String name) {
    this.name = name;  // standard Java convention
}
def __init__(self, name):
    self._name = name   # standard Python convention - self must be the
                        # first parameter of every method

The this approach is what you will see in IB exam mark schemes and textbooks.


Worked Examples

Example 1: Tracing this vs No this

With this:

public class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;  // instance variable = parameter
        this.y = y;
    }
}

Point p = new Point(3, 7);
// p.x = 3, p.y = 7 ✓
class Point():
    def __init__(self, x, y):
        self._x = x   # attribute = parameter
        self._y = y

p = Point(3, 7)
# p's _x is 3, _y is 7 ✓

Without this:

public class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        x = x;  // parameter = parameter (no effect on instance variable)
        y = y;
    }
}

Point p = new Point(3, 7);
// p.x = 0, p.y = 0 ✗ (instance variables keep default int value)
class Point():
    def __init__(self, x, y):
        x = x   # parameter = parameter (no attribute is ever created)
        y = y

p = Point(3, 7)
# p has NO _x or _y attributes at all - reading them raises an error ✗
# (Java's instance variables would still exist, holding the default 0)

Example 2: Full Class Using this Throughout

public class Employee {
    private String name;
    private double salary;
    private String department;

    public Employee(String name, double salary, String department) {
        this.name = name;
        this.salary = salary;
        this.department = department;
    }

    public String getName() { return name; }
    public double getSalary() { return salary; }
    public String getDepartment() { return department; }

    public void setSalary(double salary) {
        if (salary >= 0) {
            this.salary = salary;
        }
    }

    public void raiseSalary(double percentage) {
        // no conflict here -- percentage is not an instance variable name
        salary = salary * (1 + percentage / 100.0);
    }
}
class Employee():
    def __init__(self, name, salary, department):
        self._name = name
        self._salary = salary
        self._department = department

    def get_name(self):
        return self._name

    def get_salary(self):
        return self._salary

    def get_department(self):
        return self._department

    def set_salary(self, salary):
        if salary >= 0:
            self._salary = salary

    def raise_salary(self, percentage):
        # self. is required here too - Python never lets you drop it
        self._salary = self._salary * (1 + percentage / 100.0)

Notice: raiseSalary does not need this because percentage does not shadow any instance variable. setSalary does need it because the parameter salary shadows the field salary. (The Python version needs self. in both methods: Python makes no distinction.)


Quick Check

Q1. What does this refer to in Java?

Q2. If a constructor has String name as a parameter and the class has a private String name field, what does name = name (without this) do?

Q3. When is this required?


Spot the Error

This setter compiles but has no effect: calling setRadius(5.0) does not change the circle's radius. Click the buggy line, then pick the fix.

1public class Circle { 2 private double radius; 3 public Circle(double radius) { this.radius = radius; } 4 public void setRadius(double radius) { 5 radius = radius; 6 } 7}

Pick the fix:


Predict the Output

What does this print?

public class Pet {
    private String name;
    public Pet(String name) { this.name = name; }
    public String getName() { return name; }
}

Pet p = new Pet("Luna");
System.out.println(p.getName());

What does this print? (Notice: no this in the constructor)

public class Pet {
    private String name;
    public Pet(String name) { name = name; }
    public String getName() { return name; }
}

Pet p = new Pet("Luna");
System.out.println(p.getName());

Practice Exercises

Core

  1. Fix the bug: The following constructor has a shadowing bug. Rewrite it correctly:
    public class Car {
        private String make;
        private int year;
        public Car(String make, int year) {
            make = make;
            year = year;
        }
    }
    
  2. Identify where this is needed: In the following class, mark which lines need this and which do not. Explain why.
    public class Timer {
        private int seconds;
        public Timer(int seconds) { seconds = seconds; }
        public int getSeconds() { return seconds; }
        public void addTime(int extra) { seconds = seconds + extra; }
        public void reset(int seconds) { seconds = seconds; }
    }
    

Extension

  1. Full class with this: Write a Movie class with attributes title, director, and rating (double, 0-10). Write a parameterised constructor using this, getters, and a setter setRating(double rating) that validates the range. All parameter names should match the attribute names.

Challenge

  1. Trace and explain: A class has this code:
    public class Pair {
        private int a;
        private int b;
        public Pair(int a, int b) { this.a = a; this.b = b; }
        public void swap() {
            int temp = a;
            a = b;
            b = temp;
        }
    }
    

    Trace Pair p = new Pair(3, 7); p.swap(); and state the final values of a and b. Does swap() need this? Why or why not?


Connections

  • Prerequisites: Constructors: this is most commonly used inside constructors
  • Prerequisites: Classes and Objects: understanding instance variables and methods
  • Next: Encapsulation. this enables the getter/setter pattern that encapsulation relies on
  • Related: Inheritance. this refers to the current object even in inherited methods; super refers to the parent

© EduCS.me — A resource hub for Computer Science education

This site uses Just the Docs, a documentation theme for Jekyll.