Q8 of 40 · Core Java

Explain Java's access modifiers — public, protected, package-private, and private.

Core JavaJunioraccess-modifiersencapsulationoopjava-fundamentals

Short answer

Short answer: private restricts access to the declaring class only. Package-private (no modifier) allows access within the same package. protected allows same-package access plus subclasses in other packages. public allows access from anywhere. Choose the most restrictive modifier that still satisfies the design.

Detail

Access modifiers control visibility — who can read or call a member. Java has four levels, from most to least restrictive:

Modifier Same class Same package Subclass (other pkg) Everywhere
private
(none)
protected
public

Package-private (no modifier) is the default for class members and is easily overlooked. It's useful for package-internal helpers that shouldn't be part of a public API. Test code in the same package can access package-private members directly — this is the intended mechanism for testing internals without reflection.

Principle of least privilege: always start with private and widen only when forced. Overly permissive access is a common source of tight coupling — if everything is public, refactoring becomes painful because anything might be depending on those internals.

In test automation, this appears in two contexts: (1) Page Object locators should be private — tests interact through public methods, not raw selectors. (2) If you need to test a package-private method, put the test class in the same package as the production class (src/test/java/com/example/ mirrors src/main/java/com/example/) and access it directly without @VisibleForTesting hacks.

// EXAMPLE

AccessModifiers.java

public class LoginPage {
    // private — only this class accesses the locator strings
    private static final String EMAIL_INPUT = "[data-testid='email']";
    private static final String PASSWORD_INPUT = "[data-testid='password']";
    private static final String SUBMIT_BUTTON = "[data-testid='login-btn']";

    private final Page page;  // page reference — nobody else needs this

    // protected — subclasses (e.g. AdminLoginPage) can reuse this setup
    protected LoginPage(Page page) {
        this.page = page;
    }

    // public — the API that tests use
    public void login(String email, String password) {
        page.fill(EMAIL_INPUT, email);
        page.fill(PASSWORD_INPUT, password);
        page.click(SUBMIT_BUTTON);
    }

    // package-private — TestUtils in the same package can call this
    // without exposing it to the whole test suite
    String currentUrl() {
        return page.url();
    }
}

// WHAT INTERVIEWERS LOOK FOR

Correct definition of all four levels, the principle of least privilege, and at least one practical example. Test-automation context (keeping locators private, using package-private for testability) shows applied understanding rather than rote memorisation.

// COMMON PITFALL

Forgetting package-private exists or confusing it with protected. Protected is frequently misunderstood as 'same package only' — it also covers subclasses in other packages, which is the main reason to use it over package-private.