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?
answer
- Four callers: same class, same package, ext-package subclass, unrelated
- Each level is a superset of the one above
- protected = package + subclass (not subclass-only)
- Cross-package protected: access via your-own-type references only
- private ⊂ default ⊂ protected ⊂ public
basics
~10 sprivate: 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 sThink 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
Reproduce the basic rows: private=class, default=package, protected adds subclasses, public=everywhere.
Draw the full four-column matrix accurately and state that the levels are nested supersets, including the package half of protected.
Explain the cross-package protected refinement (access only via own-type references) and connect the matrix to least-privilege API design.
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