Public vs Private vs Protected vs Internal in Kotlin: Key Differences
public means visible everywhere, private restricts visibility to the containing class or file, protected allows visibility in the class and its subclasses, and internal limits visibility to the same module. These modifiers control how accessible your code elements are across different parts of your program.Quick Comparison
This table summarizes the visibility scope of each Kotlin modifier.
| Modifier | Visibility Scope | Accessible From | Default Modifier |
|---|---|---|---|
| public | Anywhere | Any code in any module | Yes (default) |
| private | Only inside the class or file | Same class or file only | No |
| protected | Class and subclasses | Same class and subclasses | No |
| internal | Same module | Any code within the same module | No |
Key Differences
public is the most open modifier, allowing access from any other code, even outside the module. It is the default visibility if no modifier is specified.
private restricts access strictly to the class or file where the member is declared, hiding it from all other code. This is useful for encapsulating implementation details.
protected is like private but also allows subclasses to access the member, supporting inheritance. It is only applicable to class members, not top-level declarations.
internal restricts visibility to the same module, which is a set of Kotlin files compiled together. This is helpful for sharing code within a project but hiding it from external users.
Code Comparison
Example showing public usage in Kotlin:
open class Example { public val publicData = "Visible everywhere" private val privateData = "Visible only inside Example" protected val protectedData = "Visible in Example and subclasses" internal val internalData = "Visible inside the module" } fun main() { val example = Example() println(example.publicData) // Works // println(example.privateData) // Error: private // println(example.protectedData) // Error: protected println(example.internalData) // Works if in same module }
Internal Equivalent
Example showing internal usage and its effect:
internal class InternalExample { internal val data = "Accessible within module" } fun main() { val internalExample = InternalExample() println(internalExample.data) // Works inside the same module }
When to Use Which
Choose public when you want your code to be accessible everywhere, like APIs or libraries. Use private to hide details inside a class or file, keeping your code safe from outside changes. Pick protected when you want subclasses to access members but keep them hidden from other classes. Use internal to share code within your project module but keep it hidden from external modules or libraries.
Key Takeaways
public for the widest accessibility across all modules.private to hide implementation details inside a class or file.protected allows subclass access but hides from other classes.internal restricts visibility to the same module, useful for project encapsulation.