In Kotlin, what are the default visibility and inheritance modifiers for a top-level class declared with just `class Foo`, and why were those defaults chosen?
answer
- public + final by default
- open to allow subclassing, override to override
- members final too, open them individually
- Effective Java Item 19 — fragile base class
- no package-private; internal = module scope
basics
~10 sA plain Kotlin class is public so any code can use it, and final so nobody can subclass it. To allow subclassing you must write the keyword open.
solid answer
~40 sBy default a top-level `class Foo` is `public` (visible everywhere) and `final` (cannot be subclassed or have its members overridden). This is the opposite of Java, where classes are subclassable unless marked `final`. To permit inheritance you mark the class `open`, and each method/property you want overridable must also be `open`; the overriding member uses `override`. The defaults follow Joshua Bloch's 'design and document for inheritance or else prohibit it' — final-by-default prevents fragile-base-class bugs from accidental overriding. Visibility options are `public` (default), `internal` (same Gradle module), `protected` (subclasses), and `private`. There is no package-private. `internal` replaces Java's package-private at the module granularity.
code
kotlin · 9 linesopen class Repository { // open: subclassable
open fun find(id: Int) = id // open: overridable
fun version() = 1 // final: locked
}
class CachedRepo : Repository() {
override fun find(id: Int) = id * 2
// override fun version() ... // ERROR: version is final
}go deeper
States the two defaults (public, final) and that open enables subclassing.
Adds member-level finality, override being implicitly open, and the visibility ladder including internal.
Explains the fragile-base-class rationale and the all-open/kotlin-spring plugin for proxy-based frameworks.
Frames final-by-default as an API-evolution and binary-compatibility policy, weighing it against framework needs and module-boundary design.
## The two defaults When you write `class Foo`, Kotlin applies two implicit modifiers: - **Visibility = `public`** — the class is visible to all other code that can see its declaring scope. Kotlin's visibility modifiers are: - `public` (default): visible everywhere. - `internal`: visible within the same *module* (a Gradle/Maven compilation unit). This replaces Java's package-private but at module granularity. - `protected`: visible in the declaring class and its subclasses (not available on top-level declarations). - `private`: visible in the declaring file (for top-level) or the declaring class. - There is **no package-private** in Kotlin. - **Inheritability = `final`** — the class cannot be subclassed, and its members cannot be overridden. ## Opening a class for inheritance To subclass, mark the class `open`. Members are also final by default; mark each overridable member `open` too. The subclass uses `override`. ```kotlin open class Animal { open fun speak() = "..." fun id() = 42 // final: cannot be overridden } class Dog : Animal() { override fun speak() = "Woof" } ``` ## Why final-by-default? This follows *Effective Java* Item 19: "Design and document for inheritance or else prohibit it." Subclassing that the base author didn't anticipate creates the **fragile base class problem** — internal changes silently break subclasses. Making `final` the default forces a deliberate `open` opt-in, so inheritance is always intentional and documented. ## Related keywords - `abstract` classes/members are implicitly `open` (you must override them). - `override` members are themselves `open` again unless you mark them `final override` to stop the chain. - `sealed` is a restricted form of `open` where all subclasses must be known at compile time. - The Gradle `all-open`/`kotlin-spring` compiler plugin auto-opens annotated classes (e.g. Spring `@Component`) so you don't sprinkle `open` everywhere for proxying.
- How does Kotlin's `internal` differ from Java's package-private?`internal` is visible across the whole module (compilation unit), not just one package; Java's package-private is limited to a single package.
- If a method is `open` in the base and you `override` it, can a further subclass override it again?Yes — an `override` member is implicitly `open`. Write `final override` to stop further overriding.
A Kotlin class is like a sealed appliance: you can use it but can't pry it open to modify internals unless the maker added a removable panel (open).
saying these in an interview costs you the question
- Saying Kotlin classes are open/subclassable by default like Java
- Claiming the default visibility is package-private
- Thinking `open` on the class alone makes all members overridable
- Believing `internal` means package-private
- Not knowing `abstract` members are implicitly open