Classes and objects
Classes in Kotlin offer many improvements over those in Java, resulting in more compact and better code.
Kotlin, like Java, is an object-oriented programming language (and has a remarkable number of functional programming features!).
So of course, it offers classes with encapsulation, inheritance, polymorphism and all other object-oriented paradigms, also known from Java.
The syntax, on the other hand, is a bit different, enabling you to write more compact, easier-to-read and, on the whole, simply better code.
A simple example class
class Person {
val firstName = "Alex"
val lastName = "Example"
}
As in Java, the declaration of a class starts with the keyword class
followed by its name (Person
).
Our example class Person
has two fields - more precisely: properties (see later) - of type String
named firstName
and lastName
.
public
is the default
The first difference to Java is the visibility of those fields:
While in Java those would be package-private
, since nothing else is specified, the default in Kotlin is public
, so that any properties and functions not declared otherwise are always publicly visible.
However, this class is extremely inflexible and thus meaningless: the two properties have fixed values that are assigned to them when creating an instance and, being immutable, they cannot be reassigned at all.
So the class needs a constructor:
Constructors
Unlike Java, Kotlin makes a distinction between the so-called primary constructor and any secondary ones.
The primary constructor of a class can be written very concisely by simply appending its arguments directly to the class name:
class Person(fn: String, ln: String) { // primary constructor
val firstName = fn
val lastName = ln
}
The parameters noted there (fn
and ln
in the example) can be accessed in the class body, so that the name of a person can now be specified individually when creating an instance.
Declaring properties directly in the constructor
For the common case of directly assigning constructor arguments to properties, Kotlin offers a very compact and useful alternative syntax:
class Person(val firstName: String, val lastName: String)
This does not only declare a primary constructor with two parameters, these two parameters are also declared directly to properties of the class - simply by the prefix val
(or var
).
So this example is identical to the previous one.
The class has become so short and compact that even the entire class body including the {}
can be omitted - it remains a correctly declared Kotlin class!
It might look somewhat more accustomed with a few line breaks added:
class Person (
val firstName: String,
val lastName: String
)
Data classes
We can take this one step further by writing the keyword data
before that (already very compact) class:
data class Person(val firstName: String, val lastName: String)
With this minimal addition, we have created a so-called data class. Such are extremely useful for classes whose primary task is that of a data container.
Data classes have a lot of useful features for that purpose. One, however, is a real relief for Java developers:
The Kotlin compiler automatically generates proper equals()
and hashCode()
methods!
To do this, it considers all the properties declared in the primary constructor, so that, for example, two instances of our Person
data class are structurally equal if their firstName
and lastName
match.
As a further addition, a toString()
method is also created, in the form Person(firstName = Alex, lastName = Example)
.
Another clever one is the copy
method, which I will show you later in the book.
init
blocks
Primary constructors are a great thing and make for the utmost concise code. Unfortunately, they have the disadvantage that they cannot contain any further instructions except the implicit assignment of their arguments to properties.
To execute more complex code during initialization, one makes use of secondary constructors (see below) or so-called init
blocks:
class Person(val firstName: String, val lastName: String) {
init {
log.info("Created new person!")
}
}
These are executed during instantiation in the order in which they are declared in the class’s body - so there may be more than one init
block.
Secondary constructors
Like Java, Kotlin allows for more than one constructor for a class. These are called secondary constructors:
class Person(val firstName: String, val lastName: String) {
constructor(firstName: String, lastName: String, parent: Person) : this (firstName, lastName) {
parent.children += this
}
}
They are declared using the constructor
keyword.
If there is a primary constructor it must always be called.
To do this, reference it with this
and call it separated by a :
.
In addition to the features described, Kotlin classes have much more to offer, and the already presented syntax has even more in store. In order to do justice to the title of this book, though, I leave it at this brief introduction, which suffices to understand the upcoming chapters.