skip to content

How does Kotlin's protected modifier behave, and how does it differ from Java's protected?

level: middleimportance: should knowfreq 50%

answer

  1. protected = class + subclasses only
  2. No package access (unlike Java)
  3. Illegal at top level
  4. Overrides can widen, not narrow
  5. Kotlin protected is tighter than Java's

basics

~10 s

Kotlin's protected makes a member visible to the class and its subclasses only. Unlike Java, it does NOT add package-wide visibility, and it can't be used on top-level declarations.

solid answer

~40 s

`protected` in Kotlin means a member is visible inside the **declaring class and its subclasses** — and nothing else. It cannot be applied to **top-level** declarations (there's no class to subclass). The big difference from Java: Java's `protected` *also* grants **package-private** access, so any class in the same package can touch a protected member even without inheritance. Kotlin removed that package dimension, so Kotlin `protected` is strictly *inheritance-based*. Another subtlety: when you **override** a `protected` member you may keep it `protected` or widen it (e.g., to `public`); you cannot narrow it further. Also, a subclass can access the protected member only **through the subclass's own type hierarchy**, not via an arbitrary superclass reference in some unrelated context. Because there's no package leakage, Kotlin `protected` is a genuinely tighter contract than Java's.

go deeper

for a junior

Knows protected exposes a member to subclasses.

for a middle

Knows protected has no package dimension in Kotlin and can't be top-level.

for a senior

Explains override widening/narrowing rules and Java-interop migration consequences.

for a principal

Weighs protected vs internal for designing extensible base classes and stable inheritance contracts across modules.

## What `protected` means in Kotlin `protected` makes a member visible to: - the **declaring class**, and - **subclasses** of that class. It is **not** visible to unrelated classes, and it **cannot** be applied to top-level declarations (a top-level function/property has no class, so 'subclass' is meaningless — the compiler rejects it). ```kotlin open class Shape { protected open val sides: Int = 0 protected fun describe() = "sides=$sides" } class Triangle : Shape() { override val sides = 3 // can see & override protected fun label() = describe() // OK: subclass call } // outsideCode() { Shape().describe() } // ERROR: protected, not accessible ``` ## The Java difference (the key interview point) In **Java**, `protected` grants access to subclasses **and** to every class in the **same package** (it is effectively `protected` + package-private). In **Kotlin**, `protected` grants access to subclasses **only** — there is no package component, because Kotlin has no package-private visibility at all. So porting Java code that relied on protected-via-same-package access will break; you'd switch those usages to `internal` or `public`. | Access from… | Java protected | Kotlin protected | |---|---|---| | Declaring class | yes | yes | | Subclass | yes | yes | | Same-package non-subclass | **yes** | **no** | | Anywhere else | no | no | ## Overriding rules When overriding a `protected` member, the override **keeps protected by default** but may **widen** visibility (to `public`). It may not become more restrictive (you can't override a protected member as private). This mirrors the Liskov rule that overrides cannot tighten access. ```kotlin open class Base { protected open fun f() {} } class Sub : Base() { public override fun f() {} } // widened: allowed ``` ## Where it can't go - **Top-level** declarations: compile error. - **Members of a `final` (non-`open`) class**: legal syntactically but pointless, since the class can't be subclassed; the compiler may warn. ## Recall - Kotlin `protected` = class + subclasses, **no package access**. - Java `protected` = class + subclasses **+ same package**. - Not allowed at top level; overrides may widen, not narrow.

  • Can you declare a protected top-level function?
    No — the compiler rejects it because there is no enclosing class to be subclassed.
  • When overriding a protected method, what visibilities are allowed?
    You can keep it protected or widen to public; you cannot narrow it to private or internal in a way that reduces access.

Kotlin protected is a family heirloom passed only down the bloodline; Java's also lets the neighbors (the package) borrow it.

saying these in an interview costs you the question

  • Claiming Kotlin protected grants package access like Java
  • Saying protected works on top-level declarations
  • Thinking an override can narrow protected to private
  • Confusing protected with internal
  • Believing protected members are visible to any same-module class

context