Easy Tutorial
❮ Kotlin Tutorial Kotlin Basic Syntax ❯

Kotlin Classes and Objects

Class Definition

Kotlin classes can include: constructors and initialization blocks, functions, properties, inner classes, and object declarations.

In Kotlin, the keyword class is used to declare a class, followed by the class name:

class tutorialpro {  // Class name is tutorialpro
    // The content within the curly braces is the body of the class
}

We can also define an empty class:

class Empty

We can define member functions within a class:

class tutorialpro() {
    fun foo() { print("Foo") } // Member function
}

Class Properties

Property Definition

Class properties can be declared as mutable with the keyword var, or as immutable with the read-only keyword val.

class tutorialpro {
    var name: String = ……
    var url: String = ……
    var city: String = ……
}

We can create an instance of a class using a constructor, just like using a regular function:

val site = tutorialpro() // In Kotlin, there is no new keyword

To use a property, simply reference it by its name:

site.name           // Reference with a dot
site.url

In Kotlin, a class can have a primary constructor, as well as one or more secondary constructors. The primary constructor is part of the class header, located after the class name:

class Person constructor(firstName: String) {}

If the primary constructor has no annotations and no visibility modifiers, the constructor keyword can be omitted.

class Person(firstName: String) {
}

Getter and Setter

The complete syntax for property declaration:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

Both getter and setter are optional.

If the property type can be inferred from the initialization statement or a member function of the class, the type can be omitted. val does not allow a setter function because it is read-only.

var allByDefault: Int? // Error: An initialization statement is required, default getter and setter methods are implemented
var initialized = 1    // Type is Int, default getter and setter are implemented
val simple: Int?       // Type is Int, default getter is implemented, but must be initialized in the constructor
val inferredType = 1   // Type is Int, default getter is implemented

Example

The following example defines a Person class with two mutable variables, lastName and no. The getter method is modified for lastName, and the setter method is modified for no.

class Person {

    var lastName: String = "zhang"
        get() = field.toUpperCase()   // Convert to uppercase after variable assignment
        set

    var no: Int = 100
        get() = field                // Backend variable
        set(value) {
            if (value < 10) {       // If the incoming value is less than 10, return this value
                field = value
            } else {
                field = -1         // If the incoming value is greater than or equal to 10, return -1
            }
        }

    var heiht: Float = 145.4f
        private set
}

// Test
fun main(args: Array<String>) {
    var person: Person = Person()

    person.lastName = "wang"

    println("lastName:${person.lastName}")

    person.no = 9
    println("no:${person.no}")

    person.no = 20
    println("no:${person.no}")

}

Output:

lastName:WANG
no:9
no:-1

In Kotlin, classes cannot have fields. It provides a Backing Fields mechanism. The backup field is declared with the field keyword, and the field keyword can only be used in the accessor of the property, as in the above example:

var no: Int = 100
        get() = field                // Backend variable
        set(value) {
            if (value < 10) {       // If the incoming value is less than 10, return this value
                field = value
            } else {
                field = -1         // If the incoming value is greater than or equal to 10, return -1
            }
        }

Non-null properties must be initialized at the time of definition. Kotlin provides a delayed initialization solution using the lateinit keyword to describe properties:

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // dereference directly
    }
}

Primary Constructor

Abstraction is one of the characteristics of object-oriented programming. A class itself, or some members within a class, can be declared as abstract. Abstract members do not have a concrete implementation within the class.

Note: There is no need to mark abstract classes or abstract members with the open annotation.

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

Nested Classes

We can nest a class within another class, as shown in the following example:

class Outer {                  // Outer class
    private val bar: Int = 1
    class Nested {             // Nested class
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // Invocation format: OuterClass.NestedClass.NestedMethod/Property
    println(demo)    // == 2
}

Inner Classes

Inner classes are denoted by the inner keyword.

Inner classes hold a reference to an instance of the outer class, so they can access the outer class's member properties and methods.

class Outer {
    private val bar: Int = 1
    var v = "Member property"
    /** Nested inner class **/
    inner class Inner {
        fun foo() = bar  // Accessing outer class member
        fun innerTest() {
            var o = this@Outer // Obtaining the outer class's member variable
            println("Inner class can reference the outer class's members, for example: " + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) // 1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // Inner class can reference the outer class's members, for example: Member property
}

To eliminate ambiguity when accessing this from an outer scope, we use this@label, where @label is a label indicating the source of this.


Anonymous Inner Classes

Create anonymous inner classes using object expressions:

class Test {
    var v = "Member property"

    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}

/**
 * Define interface
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()

    /**
     * Use an object expression to create an interface object, i.e., an instance of an anonymous inner class.
     */
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("Creating an instance of an anonymous inner class with an object expression")
        }
    })
}

Class Modifiers

Class modifiers include classModifier and accessModifier:

-

classModifier: Class property modifier, indicating the characteristics of the class itself.

abstract    // Abstract class
final       // Class not inheritable, default property
enum        // Enum class
open        // Class inheritable, classes default to final
annotation  // Annotation class

-

accessModifier: Access permission modifier

private    // Visible only within the same file
protected  // Visible within the same file or subclasses
public     // Visible from all calling locations
internal   // Visible within the same module

Example

// File name: example.kt
package foo

private fun foo() {} // Visible within example.kt

public var bar: Int = 5 // This property is visible everywhere

internal val baz = 6    // Visible within the same module
❮ Kotlin Tutorial Kotlin Basic Syntax ❯