A study note based on Kotlin Class Documnet.

1 Classes and Inheritance

1.1 Constructors

The optional primary constructor is part of the class header. The constructor keyword is optional if it doesn’t have any annotations or visibility modifiers. The primary constructor cannot contain any code. Initialization code must be in initializer blocks which are prefixed with the init keyword.

You can have multiple init blocks that are executed in the order of positions. Initializer blocks are parts of the primary constructor.

Properties can be defined inside the primary constructor using val or var.

Constructors inside the class body are secondary constructors. They must delegate to the primary constructor using this keyword if there is one.

If no constructors defined, a default public primary constructor with no arguments will be generated.

To create an instance of a class, call the constructor as if it were a regular function.

Class can contain the following members:

  • Constructors and initializer blocks
  • Functions
  • Properties
  • Nested and Inner Classes
  • Object Declarations

1.2 Inheritance

All classes have a common superclass Any that is the default superclass for a class with no supertype declared. Any has three methods: equals(), hashCode() and toString().

By default, classes are final: they can’t be inherited. To make a class inheritable, mark it with the open keyword.

To declare an explicit supertype, place the type after :. There is a space before and after the :. If the derived class has no primary constructor, then each secondary constructor has to initialize the base type using the super keyword or to delegate to another constructor which does that.

To override a function or a property, use explicit modifier open in the supertype and override in the subtype. You should avoid using open members in the constructors, perperty initializer, and init blocks.

Inside an inner class, use super@Outer to access superclass of the outerclass. If a class inherits multiple implementations of the same member from its immediate superclasses, it must override this member and provide its own implementation (perhaps, using one of the inherited ones). Use super<ClassTypeName> to access supertype.

An abstract class is open and can have abstract open members.

If you want define a function that can be called without having a class instance but needs access the class internals, you can write it as a member of an object declaration inside that class. Companion object allows you to access an object’s member using only the class name as a qualifier.

1.3 Properties

The syntax for a property is

1
2
3
var | val <propertyName>[: <PropertyType>] [= <property_initializer>]
    [get() = ...]
    [set(value) {...}]

You can only define a field as a backing field of a property.

Use const val to define a read-only compile-time constant. It must be at the top level or a member of an object declaration or a companion object. It must be a value of type String or a primitive type.

For a non-null property or local variable that can not be set inconstructor, use lateinit keyword for a late-initilized property.

1.4 Single Abstract Method (SAM) Interface

A SAM interface is also called a functional interface. It can have serveral non-abstract members but only one abstract member. Kotlin SAM conversion allows you to use a lambda expression block after the interface name to define an instance of a functional interface.

1.5 Visibility Modifiers

Classes, objects, interfaces, constructors, functions, properties and setters can have visibility modifiers. In all places, public is the default: it is visible everywhere.

At package level:

  • private: inside the file
  • internal: same module – a source set in a Gradle project.

At class and interface level:

  • private: inside class
  • protected: inside and subclass
  • internal: inside the module

2 Extensions

Kotlin uses an extension to add functions or properties to a class. To declare an extension function, you need to prefix its name with a receiver type. The this keyword represents an receiver object. Extension functions are dispatched statically, i.e., they are not virtual by receiver type. They are determined by the declared type.

Members have higher priority than extensions.