Encapsulation: private fields, getters, setters
Protect your data
- Encapsulation means hiding an object's data and only changing it through methods.
privateblocks direct access from unrelated outside code. It does not validate values: constructors and mutating methods must enforce the object’s rules themselves.- The main tools are the words
privateandpublic.
private fields
- Mark instance variables
privateso code in unrelated classes cannot touch them directly. - Methods inside the same class can still use them.
- This is the normal style for AP CSA: fields are
private. The first example deliberately accepts a negative start;mainis in the same class, so it can read that private field. It prints-50.0, exposing the missing validation.
public class BankAccount {
private double balance; // hidden from outside code
public BankAccount(double start) {
this.balance = start;
}
public static void main(String[] args) {
BankAccount account = new BankAccount(-50);
System.out.println(account.balance); // -50.0: private alone does not validate
}
}
Accessors (getters)
- A field is private, so we add a
publicmethod to read it. - A method that returns a field is called an accessor or getter.
- It usually starts with
get, likegetBalance().
public class BankAccount {
private double balance;
public BankAccount(double start) {
this.balance = start;
}
public double getBalance() {
return this.balance;
}
public static void main(String[] args) {
BankAccount account = new BankAccount(100);
System.out.println(account.getBalance()); // 100.0
}
}
Mutators (setters)
- A method that changes object state is a mutator. A setter is one kind, usually setting a field to a supplied value;
depositis a mutator that adds to the balance. - It can check the new value first and refuse a bad one.
- Below, the constructor rejects a negative start and
depositignores nonpositive amounts. These examples assume finitedoublevalues; the checks shown enforce the stated rules, not every possible banking requirement.
public class BankAccount {
private double balance;
public BankAccount(double start) {
if (start < 0) {
throw new IllegalArgumentException("Start must be nonnegative");
}
this.balance = start;
}
public void deposit(double amount) {
if (amount > 0) {
this.balance = this.balance + amount;
}
}
public double getBalance() {
return this.balance;
}
public static void main(String[] args) {
BankAccount account = new BankAccount(100);
account.deposit(-500);
System.out.println(account.getBalance()); // 100.0
account.deposit(50);
System.out.println(account.getBalance()); // 150.0
try {
new BankAccount(-50);
} catch (IllegalArgumentException error) {
System.out.println("Negative start rejected");
}
}
}
static vs instance
- An instance field belongs to one object. Each object has its own.
- A
staticfield belongs to the class itself — it is shared by all objects. - Below,
countrises by 1 every time aRobotis constructed. It counts constructions, not the number of objects still alive; discarding a reference does not decrease it.
public class Robot {
private static int count = 0; // shared by all robots
public Robot() {
count = count + 1;
}
public static int getCount() {
return count;
}
public static void main(String[] args) {
Robot first = new Robot();
Robot second = new Robot();
System.out.println(Robot.getCount()); // 2 constructions
}
}
toString()
toString()returns text that describes the object.- Java calls it automatically when you print the object or join it with text using
+. The inheritedObject.toString()uses the class name,@and a hexadecimal hash code; that text is not a guaranteed memory address. - It takes no parameters and returns a
String.
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "(" + this.x + ", " + this.y + ")";
}
public static void main(String[] args) {
Point point = new Point(3, 4);
System.out.println(point); // (3, 4)
System.out.println("Point: " + point); // Point: (3, 4)
}
}
Common mistakes
- Make fields
privateand reach them through getters and setters. - A setter can check a value before storing it.
Now you try
- Fill in each class according to its stated constructor and method contract;
privatealone does not enforce it. - A hidden Harness builds the object, calls the methods, and checks the results.
- These class tasks have no standalone
mainand no Run button. Check answer compiles your class with the supplied harness, runs its calls and gives feedback. The complete examples above have their own Run buttons.
Difficulty 3/5 · 200 coins + a small bonus on first completion today
Complete BankAccount. Assume start is nonnegative and all additions fit in int. Keep balance private. deposit(amount) adds the amount only if it is greater than 0. withdraw(amount) subtracts only if the amount is greater than 0 and not more than the balance (no overdraft). getBalance() returns the balance.
Click Run to see the output here.
Difficulty 3/5 · 200 coins + a small bonus on first completion today
Complete Temperature. The constructor stores an int degrees in a private field. toString() returns the degrees followed by C — for 21 it returns 21C.
Click Run to see the output here.
Difficulty 3/5 · 200 coins + a small bonus on first completion today
Complete Widget. A private static field count starts at 0. Every time a Widget is built, the constructor adds 1 to count. The static method getCount() returns how many widgets have been built.
Click Run to see the output here.