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