Kotlin Visibility and Modifiers Tutorial: Public, Private, Protected, Internal, Open, Final, and Override


This Kotlin Visibility and Modifiers tutorial explains how to control access to classes, properties, and functions using visibility modifiers (public, private, protected, internal) and how to control inheritance behavior using open, final, and override keywords. The tutorial includes practical examples and best practices to help developers write secure, maintainable, and reusable Kotlin code.

Kotlin Visibility and Modifiers – Complete Tutorial

Visibility Modifiers

Visibility modifiers control the accessibility of classes, objects, interfaces, functions, and properties.

1. public

  1. Default modifier in Kotlin.
  2. Accessible from anywhere.

class Person {
public var name: String = "Muni"
}

fun main() {
val person = Person()
println(person.name) // Accessible
}

2. private

  1. Accessible only within the class or file (for top-level declarations).

class Person {
private var age: Int = 35

fun showAge() {
println("Age is $age")
}
}

fun main() {
val person = Person()
// println(person.age) // Error: Cannot access private property
person.showAge()
}

3. protected

  1. Accessible within the class and its subclasses.

open class Animal {
protected val type = "Animal"
}

class Dog : Animal() {
fun showType() {
println(type) // Accessible here
}
}

fun main() {
val dog = Dog()
dog.showType()
// println(dog.type) // Error: Cannot access protected property
}

4. internal

  1. Accessible within the same module.

internal class Vehicle {
internal val brand = "Toyota"
}

fun main() {
val vehicle = Vehicle()
println(vehicle.brand) // Accessible within same module
}

Best Practices for Visibility

  1. Keep properties and methods as private by default.
  2. Use public only for API-facing members.
  3. Use protected for inheritance purposes.
  4. Use internal to expose members only within a module.

Modifiers Controlling Inheritance

1. open

  1. Allows classes and methods to be inherited or overridden.
  2. By default, all classes and functions are final.

open class Vehicle {
open fun drive() {
println("Vehicle is driving")
}
}

class Car : Vehicle() {
override fun drive() {
println("Car is driving fast")
}
}

2. final

  1. Prevents further inheritance or overriding.
  2. Default for all classes and functions.

open class Vehicle {
final fun start() {
println("Starting vehicle")
}
}

class Car : Vehicle() {
// override fun start() {} // Error: Cannot override final function
}

3. override

  1. Used to override an open method or property in a subclass.

open class Animal {
open fun sound() = println("Some sound")
}

class Dog : Animal() {
override fun sound() = println("Bark")
}

fun main() {
val dog = Dog()
dog.sound()
}

Best Practices for Modifiers

  1. Prefer final for classes and methods unless inheritance is required.
  2. Mark only necessary methods as open to prevent accidental overrides.
  3. Always use override explicitly when overriding a method.

Summary

This chapter explained Kotlin’s visibility modifiers (public, private, protected, internal) and inheritance-related modifiers (open, final, override). Proper use of these modifiers ensures code security, clarity, and maintainability while providing controlled flexibility in object-oriented designs.