Phase 3 · Object-Oriented KotlinModule 19~28 min read

Visibility, Nested & Inner Classes

Control access with visibility modifiers and organize code with nested and inner classes.

What you'll learn

Good design means exposing only what you intend. This module covers Kotlin's visibility modifiers — including the module-level internal that Java lacks — and how to organise code with nested and inner classes.

By the end you'll be able to:

  • Control access with the four visibility modifiers
  • Use internal for module-wide visibility
  • Distinguish nested classes from inner classes

Visibility modifiers

Visibility decides who can see a class, function, or property. Unlike Java (where the default is package-private), Kotlin's default is public. Choosing the tightest level that works keeps your public surface small and your internals free to change:

ModifierVisible…
publiceverywhere (the default)
internalanywhere in the same module
protectedin the class and its subclasses
privatein the class (or file, for top-level) only
BankAccount.kt
class BankAccount {
    private var balance = 0.0        // hidden from outside the class

    fun deposit(amount: Double) {    // public by default
        if (amount > 0) balance += amount
    }

    fun getBalance() = balance
}

val acc = BankAccount()
acc.deposit(100.0)
// acc.balance                      // ERROR — balance is private
println(acc.getBalance())           // 100.0

Tip

Start private and open up only when needed. It's far easier to loosen access later than to tighten a member half your codebase already depends on.

internal — module visibility

internal is a Kotlin addition Java doesn't have: it makes something visible everywhere in the same module (a compiled unit — a Gradle module, a library) but hidden from other modules that depend on it. It's ideal for a library's internal helpers — public within the library, invisible to its users.

Nested vs inner classes

You can declare a class inside another. There's an important distinction: a plain nested class is just grouped inside — it can't touch the outer instance. Adding inner gives it a reference to the outer object, so it can use the outer's members:

Nested vs inner

Nested (default)

A class inside a class. Cannot access the outer instance's members. Just grouping.

Outer.Nested()

inner

Marked inner. Holds a reference to the outer instance and can use its members.

Outer().Inner()

Outer.kt
class Outer {
    private val secret = "hidden"

    class Nested {                   // nested: NO access to Outer's members
        fun show() = "I'm nested"
    }

    inner class Inner {              // inner: CAN access Outer's members
        fun reveal() = "Secret is $secret"
    }
}

println(Outer.Nested().show())       // create nested directly
println(Outer().Inner().reveal())    // inner needs an Outer instance

Note

This is the opposite default from Java, where a nested class is implicitly "inner." In Kotlin you must opt in with the inner keyword — which avoids accidental references to the outer instance (a common source of memory leaks in Android). Reach for inner only when you genuinely need the outer object.

Recap & quick check

Key takeaways

  • Kotlin's default visibility is public (unlike Java's package-private).
  • The modifiers: public (everywhere), internal (same module), protected (class + subclasses), private (class/file).
  • internal is Kotlin-specific: visible within the module, hidden from other modules — great for library internals.
  • A nested class is just grouped inside and can't access the outer instance.
  • An inner class holds a reference to the outer instance and can use its members — you must opt in with 'inner'.

Quick check

1. What is Kotlin's default visibility?

2. What does 'internal' mean?

3. Can a plain nested class access the outer instance's members?

4. What does the 'inner' keyword add?

5. How does Kotlin's nested-class default differ from Java's?

Excellent — you've completed Phase 3! You can design classes, model data and state, and control access like a pro. Next comes Phase 4 — Collections & Generics.