skip to content

Visibility Modifiers & internal

Kotlin's four visibilities default to public, and internal — visible within the compilation module — is the one with no Java equivalent. Interviewers follow up on how internal is actually encoded on the JVM, since it becomes public with a mangled name.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

6

What is the default visibility of a Kotlin class, function, or property when you write no modifier, and how does this differ from Java?

level: juniorimportance: must knowfreq 75%

answer

  1. No modifier = public in Kotlin
  2. Java no modifier = package-private
  3. Kotlin dropped package-private entirely
  4. internal replaces package-private
  5. Writing 'public' is redundant

basics

~10 s

In Kotlin, anything without a modifier is public, meaning visible everywhere. In Java, a member with no modifier is package-private, visible only within the same package.

solid answer

~40 s

Kotlin's four visibility modifiers are public, private, protected, and internal. The default (no keyword) is public for top-level declarations and class members, so you rarely write public explicitly. This is the opposite of Java, where omitting a modifier gives package-private (default-access) visibility, restricted to the same package. Kotlin deliberately has no package-private concept; the nearest equivalent is internal, which is module-scoped rather than package-scoped. So a Kotlin class member declared with no modifier is callable from anywhere the class itself is visible, whereas the same Java member would be hidden outside its package. Idiomatic Kotlin omits public and uses private or internal explicitly to narrow scope.

go deeper

for a junior

States that the default is public and that this differs from Java.

for a middle

Knows Kotlin has no package-private and that internal is the closest equivalent.

for a senior

Explains the design rationale and migration implications when porting Java code.

for a principal

Discusses how default-public shapes API design and the value of explicit internal/private for evolvable library surfaces.

## What 'default visibility' means Visibility (or access) modifiers control *where* a declaration can be referenced. Kotlin has exactly four: `public`, `private`, `protected`, and `internal`. When you write **no** modifier, the declaration is **`public`** — visible to any code that can see its containing scope. ```kotlin class Service { // public class val name = "x" // public property fun run() {} // public function } fun helper() {} // public top-level function ``` Because `public` is the default, writing it explicitly is redundant and most style guides (and the Kotlin compiler's lint) discourage it. ## How this differs from Java | | No modifier means… | Scope | |---|---|---| | **Kotlin** | `public` | Everywhere the declaration is reachable | | **Java** | package-private ("default" access) | Only the **same package** | Java has four levels: `public`, `protected`, *default* (package-private), `private`. Kotlin intentionally **dropped package-private** — there is no keyword for "visible within this package only." Packages in Kotlin are purely an organizational/namespacing tool, not a visibility boundary. ## The Kotlin replacement for package-private Kotlin offers **`internal`** instead: visible within the same **module** (a set of files compiled together — a Gradle source set, a Maven module, an IntelliJ module). This is broader than a package but narrower than fully public, and it's the idiomatic way to hide library internals from external consumers. ## Practical consequences - A Kotlin member with no modifier is part of your **public API**. If you don't want that, you must explicitly write `private` or `internal`. - Migrating Java code: a package-private Java member has **no exact Kotlin equivalent**; you usually map it to `internal` or `private`. ## Recall - Kotlin no-modifier ⇒ `public`. - Java no-modifier ⇒ package-private. - Kotlin has **no** package-private; use `internal`.

  • Why did Kotlin remove package-private?
    Package-private leaks across packages too easily (anyone can declare a class in your package) and packages are weak boundaries; module-scoped internal is a stronger, more meaningful unit for hiding internals.
  • Is writing 'public' an error?
    No, it compiles fine, but it's redundant and flagged by the compiler/IDE as a 'redundant visibility modifier'.

Kotlin assumes the door is open by default; Java assumes it's open only to your immediate neighbors (the package).

saying these in an interview costs you the question

  • Saying the default is private
  • Claiming Kotlin has package-private
  • Thinking no-modifier in Kotlin matches Java's no-modifier
  • Believing 'public' must be written explicitly
  • Confusing internal with package scope

context

open as a page

What does private mean for a top-level declaration versus a class member in Kotlin?

level: middleimportance: must knowfreq 65%

basics

~10 s

A private top-level declaration is visible only inside its own file. A private class member is visible only inside that class (and its members), not to subclasses or outside code.

open as a page

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

level: middleimportance: should knowfreq 50%

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.

open as a page

How do you control the visibility of a primary constructor and of a property's setter independently in Kotlin?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Put the visibility keyword before the constructor keyword to restrict a primary constructor, e.g. class C private constructor(). For a property, you can give the setter its own visibility like 'var x: Int = 0; private set' so reads are public but writes are private.

open as a page

What exactly is a 'module' for the internal modifier, and when would you choose internal over public or private?

level: seniorimportance: should knowfreq 55%

basics

~20 s

internal means visible everywhere within the same compilation module. A module is a set of files compiled together — like one Gradle source set or IntelliJ module. Use internal to expose things across your module but hide them from outside consumers.

open as a page

How do Kotlin's visibility modifiers map onto JVM bytecode access flags, and why does that matter?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Kotlin enforces visibility at compile time, then compiles to JVM access flags: public stays public, protected stays protected, but private members are sometimes public in bytecode, and internal becomes public with a mangled name. So Java can sometimes reach what Kotlin hides.

open as a page