Access Modifiers
By the end of this lesson, you'll be able to:
- Explain what public, private, and protected control
- Choose an appropriate access modifier for a field or method
- Recognize private as the safer default for internal implementation details
Prerequisites: "Properties: get and set"
The main three: private, public, protected
public class BankAccount {
private Decimal balance; // only visible inside this class
public Decimal getBalance() { // visible to any code that has a BankAccount
return balance;
}
}
public class BankAccount {— the class itself ispublic, so any code in the org can reference it.private Decimal balance;—privatemeans this field is visible only inside this class — the safest default for internal details.- (blank line)
public Decimal getBalance() {—publicmeans this method is visible to any code that has aBankAccount.return balance;— returns the private value through a controlled, public door.}— closes the method.}— closes the class.
private— visible only inside the same class.public— visible to any code, anywhere in the org.protected— visible inside the class and any class that extends it (covered in a later module on inheritance).
Why hide balance behind private?
BankAccount account = new BankAccount();
// account.balance = 1000000; // compile error — balance is private
System.debug(account.getBalance()); // fine — getBalance() is public
BankAccount account = new BankAccount();— creates an account.// account.balance = 1000000;— commented out because this line would not compile —balanceisprivate, so code outsideBankAccountcannot touch it directly.System.debug(account.getBalance());— this works fine —getBalance()ispublic.
If balance were public, any code anywhere could set it directly to anything, bypassing whatever business rules should govern it (like "never allow a negative balance"). Making it private and exposing controlled access through a public method — a pattern called encapsulation — forces every change to go through logic you control. A later module covers this principle in depth.
A real business example: Legal (Case File Access)
public class CaseFile {
private String confidentialNotes;
public String caseNumber { get; set; }
public String getSummaryForClient() {
return 'Case ' + caseNumber + ': in progress.';
}
}
public class CaseFile {— the class.private String confidentialNotes;— staysprivate— internal only, never exposed outside this class.- (blank line)
public String caseNumber { get; set; }— apublicauto-property — safe to expose.- (blank line)
public String getSummaryForClient() {— apublicmethod offering a controlled, client-safe view.return 'Case ' + caseNumber + ': in progress.';— builds a summary using only the safe, public field — neverconfidentialNotes.}— closes the method.}— closes the class.
This mirrors a real access-control need: some data (like privileged legal notes) should never be exposed outside the class that manages it.
A sensible default
When unsure, start with private and only widen access (to public or protected) once something outside the class genuinely needs it. It's far easier to loosen access later than to discover — after other code already depends on it — that a field should never have been exposed.
Bringing it together: rebuilding the Calculator project as a class
Back in Module 8's "Project: Calculator," the exact same calculation logic was written as plain, standalone statements — no method, no class, because neither had been taught yet. Now that both have been, here's that same logic, properly wrapped:
public class Calculator {
public String calculateAndFormat(Decimal a, Decimal b, String operatorSymbol) {
Decimal result;
switch on operatorSymbol {
when '+' {
result = a + b;
}
when '-' {
result = a - b;
}
when '*' {
result = a * b;
}
when '/' {
if (b == 0) {
return 'Error: cannot divide by zero.';
}
result = a / b;
}
when else {
return 'Error: unrecognized operator "' + operatorSymbol + '".';
}
}
return a + ' ' + operatorSymbol + ' ' + b + ' = ' + result.setScale(2);
}
}
public class Calculator {— new: the logic now lives inside a class instead of as loose statements.public String calculateAndFormat(Decimal a, Decimal b, String operatorSymbol) {— new: it's wrapped in a reusablepublicmethod takinga,b, andoperatorSymbolas parameters. 3-26. Theswitch on operatorSymbolblock and itswhenbranches — identical logic to Module 8's "Project: Calculator", already explained line by line there; nothing about the calculation itself changed, only where it lives.}— closes the method.}— closes the class.
Calculator calc = new Calculator();
System.debug(calc.calculateAndFormat(12, 5, '+')); // "12 + 5 = 17.00"
System.debug(calc.calculateAndFormat(10, 0, '/')); // "Error: cannot divide by zero."
Calculator calc = new Calculator();— new: aCalculatorobject is created once...System.debug(calc.calculateAndFormat(12, 5, '+'));— ...thencalculateAndFormatis called on it, callable as many times as needed instead of retyping the whole block for every calculation.System.debug(calc.calculateAndFormat(10, 0, '/'));— the same object handles a second, different calculation. This exact class is what the Apex Testing module writes real automated tests against.
Exercise
Rewrite the Book class so pageCount is private, with a public method getPageCount() that returns it.
Show hint
private Integer pageCount; public Integer getPageCount() { return pageCount; }
Access Modifiers Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
Access modifiers control who is allowed to see or use a field, method, or class — choosing the most restrictive one that still works is a core habit of writing maintainable code.