Computer scienceProgramming languagesKotlinObject-oriented programmingObject-oriented programming basic

Visibility modifiers for members

7 minutes read

All class members—fields, methods, and properties—have visibility modifiers. Visibility modifiers allow you to set a valid scope for class members. That is, they define the context in which a given variable or method can be used. Visibility modifiers are special keywords that define which part of your code is allowed to use. There are four access modifiers in Kotlin: private, protected, internal, and public.

Public members

The public keyword is used to tell the compiler that something should be available to everyone. By declaring an instance of a class as a public modifier, you can refer to any of its fields anywhere in the program where the object itself is available.

public class Student {

    public var name: String   // property is public and visible everywhere

}

Private members

Meanwhile, the private modifier is the exact opposite of public. When using private, data will only be available within a specific class. Let's complicate the previous example by adding a private access modifier and a new variable id. If properties are set through the constructor, then the visibility modifier can also be specified in the constructor for the properties:

class Student(val name: String, private val id: Int)

As you can see, here id becomes inaccessible from the outside, since it has a private modifier:

val mark: Student = Student("Mark", 01)

println("Name: ${mark.name}  Id: ${mark.id}")  //Cannot access 'id': it is private in 'Student'

To protect the fields from tampering, the private keyword is used—it makes the members of the class available only within the class itself. Now, these fields cannot be changed anywhere except in the methods of this class. However, you won't be able to get their value from the outside either, and an attempt to output will lead to an error.

We could use the backing property to define the getter and setter and add more control over the private fields.

Protected members

protected is the same as private, except it can be seen in subclasses. Here's an example:

open class Person {
    protected open val name: String = ""
    private val age: Int = 0
}

class Student : Person() {
    override val age = 18 // age is private and this will NOT work
    override val name = "Eyad" // this will work
}

class Teacher {
    private val person = Person()

    fun printPerson(): String {
        return person.name // Cannot access 'name': it is protected in 'Person'
    }
}

Internal members

The internal modifier means that who sees the declaring class sees its internal members:

class Bank {
    internal val accountNumber: Long = 5L

    internal fun getBranch(): String {
        return "Branch is Alex"
    }
}

class BankController {
    private val bank = Bank()

    fun getUserAccountNumber(): Long {
        return bank.accountNumber // same module
    }
}

Visibility of constructors in a class

You can also specify a modifier for constructors: for example, make the class primary constructor private. Remember to add an explicit constructor keyword:

class Student private constructor(val name: String) {
    var age: Int = 0

    constructor(name: String, _age: Int) : this(name) {
        age = _age
    }
}

In this case, the primary constructor is private, so it is accessible only from the same class (for example, when calling the secondary constructor). Accordingly, from the outside, to create an object of this class, you can use only the secondary constructor:

val anna: Student = Student("Anna")     //Cannot access '<init>': it is private in 'Student'
val mark: Student = Student("Mark", 23)

println("Name: ${anna.name}  Age: ${anna.age}")
println("Name: ${mark.name}  Age: ${mark.age}")

Public and private functions

Private functions are used to hide the internal low-level logic implementation from the rest of the code and make public functions more brief and readable. Here is an example with the function printInfo() and getAge(). We have set the getAge() function as private, and this function is not available from the outside. Meanwhile, the printInfo() function is open, and we can get information about the student.

fun main() {
    val anna = Student("Anna", 9, 19)
    anna.printInfo()
    anna.getAge()     //Cannot access 'getAge': it is private in 'Student'
}

class Student(
    private val name: String,
    private val id: Int,
    private val age: Int
) {

    fun printInfo() {
        println("Id: $id Name: $name")
    }

    private fun getAge() {
        print("Age: $age ")
    }
}

Keep in mind that for local variables and functions, the visibility modifier cannot be set. Local variables and functions are available only within the function in which they are defined. We will talk about inheritance and subclasses later.

Conclusion

So, let's revise the names of access modifiers:

  • public — data is available everywhere;

  • private — data is available only inside a class;

  • protected — the same as private, except data can be seen in subclasses;

  • internal -- who sees the declaring class sees its internal members.

36 learners liked this piece of theory. 4 didn't like it. What about you?
Report a typo