skip to content

Walk through the access matrix: for each access level, who can access the member — same class, same package, subclass in another package, and unrelated code in another package?

level: middleimportance: must knowfreq 78%

answer

  1. Four callers: same class, same package, ext-package subclass, unrelated
  2. Each level is a superset of the one above
  3. protected = package + subclass (not subclass-only)
  4. Cross-package protected: access via your-own-type references only
  5. private ⊂ default ⊂ protected ⊂ public

basics

~10 s

private: same class only. Default (no keyword): same package. protected: same package plus subclasses anywhere. public: everyone. Each level adds one more group of allowed callers.

solid answer

~50 s

Think of four columns of callers: (1) the same class, (2) a different class in the same package, (3) a subclass in a different package, (4) an unrelated class in a different package. private allows only column 1. Default/package-private allows columns 1 and 2. protected allows 1, 2, and 3 — it adds cross-package subclass access on top of package access. public allows all four. The two subtleties interviewers probe: default is wider than private but narrower than protected (package, no subclasses outside it); and protected is NOT 'subclasses only' — it still includes the whole package. There's also a refinement on protected across packages: a subclass can reach an inherited protected member only through references of its own type (or a subtype), not through a reference of the parent type. Picking the right column is least-privilege in practice.

go deeper

for a junior

Reproduce the basic rows: private=class, default=package, protected adds subclasses, public=everywhere.

for a middle

Draw the full four-column matrix accurately and state that the levels are nested supersets, including the package half of protected.

for a senior

Explain the cross-package protected refinement (access only via own-type references) and connect the matrix to least-privilege API design.

for a principal

Discuss how these scopes interact with module boundaries, inheritance-based extension points, and the maintenance cost of exposing protected/public surfaces to other teams.

## The mental model: four kinds of caller To reason about access precisely, imagine the member is being accessed from four distinct vantage points (callers). For each access level we ask: is this caller allowed? - **C1 — Same class:** code inside the very class that declares the member. - **C2 — Same package, different class:** another class in the same package (a *package* is Java's namespace, normally one folder of `.java` files sharing a `package` declaration). - **C3 — Subclass in a different package:** a class that `extends` the declaring class but lives in another package. (*Subclass* = a class that inherits via `extends`.) - **C4 — Unrelated class in a different package:** no inheritance, different package. ## The matrix | Access level | C1 same class | C2 same package | C3 subclass, other package | C4 unrelated, other package | |---|:---:|:---:|:---:|:---:| | `private` | ✅ | ❌ | ❌ | ❌ | | default (package-private) | ✅ | ✅ | ❌ | ❌ | | `protected` | ✅ | ✅ | ✅* | ❌ | | `public` | ✅ | ✅ | ✅ | ✅ | Notice each level is a strict **superset** of the one above it: every step down the list keeps all prior callers and admits one more group. private ⊂ default ⊂ protected ⊂ public. ## Two subtleties that trip people up **(a) `protected` is NOT 'subclasses only'.** It grants same-package access (C2) *and* cross-package subclass access (C3). Many people forget the package half. So a sibling class in the same package can touch a protected member even with no inheritance. **(b) The protected-across-packages refinement (the `*`).** When a subclass in another package accesses an *inherited* protected member, it may do so only **through a reference whose static type is the subclass itself (or a further subtype)** — not through a reference typed as the superclass. This stops a subclass from using `protected` as a backdoor into *sibling* instances of the parent. ```java package a; public class Base { protected int x; } package b; import a.Base; public class Sub extends Base { void demo(Sub s, Base b) { this.x = 1; // OK: own inherited member s.x = 2; // OK: reference typed as Sub (the subclass) // b.x = 3; // COMPILE ERROR: b is typed as Base, another package } } ``` ## Why this matters Knowing the exact column each level grants is what lets you apply **least privilege** correctly: choose the narrowest level whose 'allowed callers' still covers your real collaborators, and no wider. Over-granting (e.g. `public` when `private` would do) leaks internals into other packages/teams and freezes your ability to change them.

  • Can a class in the same package access a protected member without extending the class?
    Yes. protected includes full same-package access, so inheritance is not required within the package.
  • Why can't a cross-package subclass access a protected field through a superclass-typed reference?
    The JLS restricts cross-package protected access to references of the subclass's own type (or a subtype), preventing a subclass from reaching into unrelated sibling instances of the parent.

saying these in an interview costs you the question

  • Saying protected means 'subclasses only' and forgetting same-package access
  • Thinking a cross-package subclass can read protected members off a superclass-typed reference
  • Believing default allows subclass access outside the package (it does not)
  • Treating the four levels as unrelated rather than nested supersets

context