Object-Oriented Basics
The this Keyword
Current Object Reference
Your setter has void setName(String name). Inside, which name is which?
The this keyword refers to the current object, letting you write
this.name = name to distinguish the field from the parameter.
Disambiguate fields from parameters
Use this.field when names conflict.
public class Disambiguate {
public static void main(String[] args) {
System.out.println("=== Disambiguating with 'this' ===\n");
// Without 'this', names would shadow fields
Person person = new Person("Alice", 30);
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
// Update using setters
person.setName("Bob");
person.setAge(25);
System.out.println("\nAfter update:");
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
System.out.println("\n=== Why Same Names? ===");
System.out.println("✓ Clear what the parameter represents");
System.out.println("✓ No need to invent different names");
System.out.println("✓ Common convention in Java");
}
}
class Person {
private String name;
private int age;
// Parameters have same name as fields
Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter - no disambiguation needed
public String getName() {
return name; // Just 'name' is fine here
}
public int getAge() {
return age;
}
// Setter - needs 'this' to disambiguate
public void setName(String name) {
this.name = name; // this.name = field, name = parameter
}
public void setAge(int age) {
this.age = age;
}
}
this.name is the field. name alone is the parameter.
Method chaining
Return this to enable fluent interfaces.
public class MethodChaining {
public static void main(String[] args) {
System.out.println("=== Method Chaining ===\n");
int addAmount = ;
// Traditional way: separate statements
Counter counter1 = new Counter();
counter1.increment();
counter1.increment();
counter1.add(addAmount);
System.out.println("Traditional: " + counter1.getValue());
// Chained way: single statement
Counter counter2 = new Counter();
counter2.increment().increment().add(addAmount);
System.out.println("Chained: " + counter2.getValue());
System.out.println("\n=== String Builder Pattern ===");
// Build message fluently
MessageBuilder builder = new MessageBuilder();
String message = builder
.append("Hello")
.append(", ")
.append("World")
.append("!")
.build();
System.out.println("Message: " + message);
System.out.println("\n=== Benefits ===");
System.out.println("✓ More concise code");
System.out.println("✓ Reads like natural language");
System.out.println("✓ No need for temporary variables");
}
}
class Counter {
private int value = 0;
// Returns 'this' to enable chaining
public Counter increment() {
value++;
return this; // Return the same object!
}
public Counter add(int amount) {
value += amount;
return this; // Return the same object!
}
public Counter reset() {
value = 0;
return this;
}
public int getValue() {
return value;
}
}
class MessageBuilder {
private StringBuilder sb = new StringBuilder();
public MessageBuilder append(String text) {
sb.append(text);
return this; // Enables: append("a").append("b")
}
public MessageBuilder appendLine(String text) {
sb.append(text).append("\n");
return this;
}
public String build() {
return sb.toString();
}
}
public class MethodChaining {
public static void main(String[] args) {
System.out.println("=== Method Chaining ===\n");
int addAmount = ;
// Traditional way: separate statements
Counter counter1 = new Counter();
counter1.increment();
counter1.increment();
counter1.add(addAmount);
System.out.println("Traditional: " + counter1.getValue());
// Chained way: single statement
Counter counter2 = new Counter();
counter2.increment().increment().add(addAmount);
System.out.println("Chained: " + counter2.getValue());
System.out.println("\n=== String Builder Pattern ===");
// Build message fluently
MessageBuilder builder = new MessageBuilder();
String message = builder
.append("Hello")
.append(", ")
.append("World")
.append("!")
.build();
System.out.println("Message: " + message);
System.out.println("\n=== Benefits ===");
System.out.println("✓ More concise code");
System.out.println("✓ Reads like natural language");
System.out.println("✓ No need for temporary variables");
}
}
class Counter {
private int value = 0;
// Returns 'this' to enable chaining
public Counter increment() {
value++;
return this; // Return the same object!
}
public Counter add(int amount) {
value += amount;
return this; // Return the same object!
}
public Counter reset() {
value = 0;
return this;
}
public int getValue() {
return value;
}
}
class MessageBuilder {
private StringBuilder sb = new StringBuilder();
public MessageBuilder append(String text) {
sb.append(text);
return this; // Enables: append("a").append("b")
}
public MessageBuilder appendLine(String text) {
sb.append(text).append("\n");
return this;
}
public String build() {
return sb.toString();
}
}
public class MethodChaining {
public static void main(String[] args) {
System.out.println("=== Method Chaining ===\n");
int addAmount = ;
// Traditional way: separate statements
Counter counter1 = new Counter();
counter1.increment();
counter1.increment();
counter1.add(addAmount);
System.out.println("Traditional: " + counter1.getValue());
// Chained way: single statement
Counter counter2 = new Counter();
counter2.increment().increment().add(addAmount);
System.out.println("Chained: " + counter2.getValue());
System.out.println("\n=== String Builder Pattern ===");
// Build message fluently
MessageBuilder builder = new MessageBuilder();
String message = builder
.append("Hello")
.append(", ")
.append("World")
.append("!")
.build();
System.out.println("Message: " + message);
System.out.println("\n=== Benefits ===");
System.out.println("✓ More concise code");
System.out.println("✓ Reads like natural language");
System.out.println("✓ No need for temporary variables");
}
}
class Counter {
private int value = 0;
// Returns 'this' to enable chaining
public Counter increment() {
value++;
return this; // Return the same object!
}
public Counter add(int amount) {
value += amount;
return this; // Return the same object!
}
public Counter reset() {
value = 0;
return this;
}
public int getValue() {
return value;
}
}
class MessageBuilder {
private StringBuilder sb = new StringBuilder();
public MessageBuilder append(String text) {
sb.append(text);
return this; // Enables: append("a").append("b")
}
public MessageBuilder appendLine(String text) {
sb.append(text).append("\n");
return this;
}
public String build() {
return sb.toString();
}
}
return this allows obj.setX(1).setY(2).setZ(3).
Pass this to other methods
Give the current object to another method or class.
public class PassThis {
public static void main(String[] args) {
System.out.println("=== Passing 'this' to Methods ===\n");
// Create registrar and tasks
TaskRegistry registry = new TaskRegistry();
Task task1 = new Task("Learn Java", registry);
Task task2 = new Task("Practice coding", registry);
Task task3 = new Task("Build projects", registry);
System.out.println("=== Registry Status ===");
registry.showAll();
System.out.println("\n=== Completing a Task ===");
task2.complete();
System.out.println("\n=== Registry After Completion ===");
registry.showAll();
}
}
class Task {
private String name;
private boolean completed = false;
Task(String name, TaskRegistry registry) {
this.name = name;
registry.register(this);
}
void complete() {
completed = true;
System.out.println("Completed: " + name);
}
String getStatus() {
return name + (completed ? " [DONE]" : " [pending]");
}
}
class TaskRegistry {
private Task[] tasks = new Task[10];
private int count = 0;
void register(Task task) {
if (count < tasks.length) {
tasks[count++] = task;
System.out.println("Registered: " + task.getStatus());
}
}
void showAll() {
System.out.println("All tasks (" + count + "):");
for (int i = 0; i < count; i++) {
System.out.println(" " + (i + 1) + ". " + tasks[i].getStatus());
}
}
}
someMethod(this) passes the current object as an argument.
Call another constructor
Use this() to invoke a different constructor.
public class ThisConstructor {
public static void main(String[] args) {
System.out.println("=== this() Constructor Calls ===\n");
// Different ways to create Rectangle
Rectangle r1 = new Rectangle();
System.out.println("1. " + r1);
Rectangle r2 = new Rectangle(5); // Square
System.out.println("2. " + r2);
Rectangle r3 = new Rectangle(4, 6);
System.out.println("3. " + r3);
System.out.println("\n=== Notice Constructor Chain ===");
System.out.println("Each simpler constructor calls a more complete one.");
System.out.println("All eventually reach the main constructor.");
}
}
class Rectangle {
private double width;
private double height;
// Main constructor - all logic here
Rectangle(double width, double height) {
System.out.println(" [Main constructor: " + width + "x" + height + "]");
this.width = Math.max(0, width); // Validation
this.height = Math.max(0, height);
}
// Square constructor - delegates to main
Rectangle(double side) {
this(side, side); // Must be FIRST statement!
System.out.println(" [Square constructor]");
}
// Default constructor - delegates to square
Rectangle() {
this(1); // Unit square
System.out.println(" [Default constructor]");
}
@Override
public String toString() {
return "Rectangle " + width + "x" + height;
}
}
this(args) calls another constructor. Must be first line.
Builder pattern
Combine method chaining with a separate builder class.
public class BuilderPattern {
public static void main(String[] args) {
System.out.println("=== Builder Pattern ===\n");
// Build an email step by step
Email email = new EmailBuilder()
.from("alice@example.com")
.to("bob@example.com")
.subject("Meeting Tomorrow")
.body("Hi Bob,\nLet's meet at 10am.\n- Alice")
.priority(EmailBuilder.Priority.HIGH)
.build();
System.out.println(email);
System.out.println("\n=== Another Email ===");
// Simpler email with defaults
Email simple = new EmailBuilder()
.to("team@example.com")
.subject("Quick update")
.build();
System.out.println(simple);
System.out.println("\n=== Benefits ===");
System.out.println("✓ Optional parameters made easy");
System.out.println("✓ Readable, self-documenting");
System.out.println("✓ Immutable result object");
}
}
class EmailBuilder {
// Builder fields with defaults
private String from = "noreply@example.com";
private String to = "";
private String subject = "(no subject)";
private String body = "";
private Priority priority = Priority.NORMAL;
enum Priority { LOW, NORMAL, HIGH, URGENT }
// Each setter returns 'this'
public EmailBuilder from(String from) {
this.from = from;
return this; // Enable chaining
}
public EmailBuilder to(String to) {
this.to = to;
return this;
}
public EmailBuilder subject(String subject) {
this.subject = subject;
return this;
}
public EmailBuilder body(String body) {
this.body = body;
return this;
}
public EmailBuilder priority(Priority priority) {
this.priority = priority;
return this;
}
// Final build method creates the object
public Email build() {
if (to.isEmpty()) {
throw new IllegalStateException("'to' is required");
}
return new Email(from, to, subject, body, priority.name());
}
}
class Email {
private final String from, to, subject, body, priority;
Email(String from, String to, String subject, String body, String priority) {
this.from = from;
this.to = to;
this.subject = subject;
this.body = body;
this.priority = priority;
}
@Override
public String toString() {
return String.format(
"=== Email [%s] ===\nFrom: %s\nTo: %s\nSubject: %s\n---\n%s",
priority, from, to, subject, body.isEmpty() ? "(no body)" : body
);
}
}
Builder accumulates settings, then creates the final object.
Exercise: CompleteExample.java
Comprehensive example combining all uses of this