Skip to main content

SF-0305 · Concept · Easy

Explain more about private access modifiers?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

The private keyword in Apex restricts a member — a method, field, inner class, or property — to the class that declares it. Code in any other class, package, or trigger cannot see or call a private member. It’s also the default for any class member that doesn’t explicitly state an access modifier.

The rule

public class OrderService {
    private Decimal taxRate = 0.18;          // visible only inside OrderService

    private Decimal calculateTax(Decimal amt) {
        return amt * taxRate;
    }

    public Decimal totalWithTax(Decimal amt) {
        return amt + calculateTax(amt);      // OK — same class
    }
}

Another class cannot do:

OrderService svc = new OrderService();
svc.calculateTax(100);   // compile error: Method is not visible
svc.taxRate;             // compile error: Variable is not visible

What private applies to

  • Member methods — only invokable from the same class.
  • Member fields — only readable/writable from the same class.
  • Inner classes — only usable inside the outer class.
  • Properties — getters and setters can each have their own modifier.
  • Constructors — only callable from the same class (used for singleton patterns).

What private does NOT apply to

  • Top-level (outer) Apex classes. A top-level class is either public or global. private on a top-level class is a compile error. Encapsulation at that level is achieved by public + careful method/field visibility.

    // Not allowed:
    // private class OrderService {}
    
    // Use:
    public class OrderService {
        private Decimal taxRate;  // visibility controlled inside
    }

Why default to private

Three reasons:

  1. Refactoring freedom. Code outside the class cannot have come to depend on a private method, so you can rename or restructure private methods without breaking callers.
  2. Smaller API surface. Less to test, less to document, less to maintain backward compatibility for.
  3. Clear public contract. When the only public methods are the ones meant to be called, the class’s intended use is obvious at a glance.

The conventional approach in mature Apex codebases: private for everything by default, escalate to public only when something genuinely needs to be called from outside the class.

@TestVisible — the unit-test escape hatch

A private member can be marked @TestVisible to let test classes call it without changing the production access level:

public class OrderService {
    @TestVisible
    private Decimal calculateTax(Decimal amt) {
        return amt * 0.18;
    }
}

@isTest
class OrderServiceTest {
    @isTest static void taxCalculation() {
        OrderService svc = new OrderService();
        Decimal tax = svc.calculateTax(100); // works only in test context
        System.assertEquals(18, tax);
    }
}

@TestVisible keeps the method private for everyone except @isTest classes — your encapsulation stays intact in production, but tests can probe internals.

private vs protected vs public vs global

ModifierSame classSame package (managed)Subscriber org code
privateYesNoNo
protectedYesYes (subclasses only)No
publicYesYesNo (unless global)
globalYesYesYes

protected is rarely used — it only matters inside an inheritance chain.

Common interview follow-ups

  • Is private the default?Yes, for class members. Top-level classes default to nothing (must be public or global).
  • Can I mock a private method in a unit test? — Yes, with the Apex Stub API for @TestVisible private methods, or by injecting an interface dependency.
  • Why does Apex make me write private if it’s the default? — Explicit access modifiers are clearer; many style guides require them. Most teams write private even where it’s redundant.

What interviewers are really looking for

The basic answer is “visible only within the class.” Strong signals: (1) default for members but not top-level classes, (2) the @TestVisible annotation as the right way to expose private to tests, (3) the convention to default to private and escalate to public only when external callers exist, (4) the difference between private (same class only) and protected (subclasses too).

Verified against: Apex Developer Guide — Access Modifiers. Last reviewed 2026-05-17.