Skip to main content

class / object

Modifiers

We can declare constants with const modifier, and it's going to be substituted with the value on the JVM level. It works only for primitive types.

modifierexplanation
finalcannot be overridden (is sed by default)
opencan be overridden
abstractmust be overridden (can't have implementation)
overrideoverrides a member in a superclass or interface (mandatory)
modifierclass membertop-level declaration
publicvisible everywherevisible everywhere
internalvisible in the modulevisible in the module
protectedvisible in subclasses (only)
privatevisible in the classvisible in the file
kotlin modifierjvm level
publicpublic
protectedprotected
privateprivate / package private
internalpublic & name ruining

enum class

In kotlin enum is a modifier for classes to create enumerations

value class

Inline classes are used to "wrap" a primitive value like String.

@JvmInline
value class Password(private val s: String)

// No actual instantiation of class 'Password' happens
// At runtime 'securePassword' contains just 'String'
val securePassword = Password("Don't try this in production")

data class

Generates equals, hashCode, copy, toString

equals and reference equality

In kotlin == calls equals. There is also === operator which checks reference equality. Bare class eqauls uses reference equality check.

val set1 = setOf(1, 2, 3)
val set2 = setOf(1, 2, 3)

set1 == set2 // true
set1 === set2 // false

We can still exclude props from the basic methods in a data classby moving them outside the primary constructor.

data class User(val email: String) {
val nickname: String? = null
}

sealed class

Restricts class hierarchy, all subclasses must be located in the sames file.

Class delegation with by

We can delegate methods from one class another. We don't need to write boilerplate code for it.

interface Printer {
fun printMessage(message: String)
}

class ConsolePrinter : Printer {
override fun printMessage(message: String) {
pirntln(message)
}
}

class PrinterManager(printer: Printer) : Printer by printer

fun main() {
val consolePrinter = ConsolePrinter()
val manager = PrinterManager(consolePrinter)

manager.printMessage("Hi there!") // <-- we are calling a method, the code of which
// we did not write in PrinterManager explicitly
}

Package structure

In kotlin we can put multiple classes inside one file, this file can also contain top-level statements

Inheritance

interface Base
class BaseImpl : Base
open class Parent
class Child : Parent() // <-- () is the constructor call, so we can pass parameters there if any

object

object = singleton

java

public class JSingleton {
public final static JSingleton INSTANCE = new JSingleton();

private JSignleton() {
}

private foo() {
}
}

kotlin

object KSingleton {
fun foo() {}
}

companion object

In kotlin there are no static methods and companion objects might be a replacement for that.

class A {
companion object {
fun foo() = 1
}
}

fun main(args: Array<String>) {
A.foo()
}

Companion objects can implement interfaces and be receiver of extension function.

interface Factory<T> {
fun create(): T
}

class A {
private constructor()

companion object : Factory<A> {
override fun create(): A {
return A()
}
}
}

fun <T> createNewInstance(factory: Factory<T>) { /* some code */
}

createNewInstance(A)
A.create()
class Person(val firstName: String, val lastName: String) {
companion object {}
}

fun Person.Companion.fromJson(json: String): Person {
// ...
}

val p = Person.fromJson(json)

Not all objects are singletons, object expressions are the java's anonymous class alternative. They are used for the cases when we have to override multiple methods, otherwise we could just use lambdas.

widnow.addMouseListener() {
object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ..
}

override fun mouseEntered(e: MouseEvent) {
// ..
}
}
}

Functions

There are no static members in kotlin. The closest thing to that would be:

  • top-level statements
  • objects' members
  • companion objects' members

Calling a top-level function from Java:

package intro

fun foo() = 0
packge other;

import intro.MyFileKt;

public class UsingFoo {
public static void main(String[] args) {
MyFileKt.foo();
}
}

We can use the @JvmName to change the name of the package to import.

@file:JvmName("Util")

package intro

fun foo() = 0
packge other;

import static intro.Util;

public class JavaUsage {
public static void main(String[] args) {
into i = Util.foo();
}
}

Constructors

class A

val a = A() // <-- calling a default constructor

Full primary constructor syntax looks like this. val or var in the constructor would automatically create a property. Constructor's visibility can be changed.

class Person(name: String) { // <-- name is a constructor parameter
val name: String

init {
this.name = name
}
}

We can declare secondary constructors and must use the primary constructor.

class Rectangle(val height: Int, val width: Int) {
constructor(side: Int) : this(side, side) { /* some logic */
}
}

Properties

Kotlin

contact.address
contact.address = "..."

Java

contact.getAddress();
contact.

setAdderss("...");

property = accessor(s)

val = getter

var = getter + setter

If the field is not mentioned in custom accessor then no backing field is generated. All properties are open.

Lazy and late initialization

Lazy props' values is calculated on the first access.

val lazyValue: String by lazy {
println("completed!")
"Hello"
}

lateinit is useful when we want to initialize the values not in the constructor and not to use nullable accessors everywhere. If the property was not initialize a runtime UninitializedPropertyAccessException is thrown. lateinit can't be val, can't be nullable or of a primitive type.

class KotlinActivity : Activity() {
lateinit var myData: MyData

override fun onCreate(savedInstanceState: Budnle?) {
super.onCreate(savedInstanceState)

myData = intent.getParcelableExtra("MY_DATA")
}
}
myData.foo // we can call props of myData with no safe accessors