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.namealways refers to the instance variable. Plainnamerefers to the closest scope: inside a constructor or method with anameparameter, that means the parameter. Outside such a context, plainnameandthis.nameare 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.
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
- 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; } } - Identify where
thisis needed: In the following class, mark which lines needthisand 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
- Full class with
this: Write aMovieclass with attributestitle,director, andrating(double, 0-10). Write a parameterised constructor usingthis, getters, and a settersetRating(double rating)that validates the range. All parameter names should match the attribute names.
Challenge
- 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 ofaandb. Doesswap()needthis? Why or why not?
Connections
- Prerequisites: Constructors:
thisis most commonly used inside constructors - Prerequisites: Classes and Objects: understanding instance variables and methods
- Next: Encapsulation.
thisenables the getter/setter pattern that encapsulation relies on - Related: Inheritance.
thisrefers to the current object even in inherited methods;superrefers to the parent