In Part 3, I introduced some aspects of object-oriented programming (OOP) for Kotlin. In this article, I will continue to introduce other aspects of OOP.


We can use interfaces the way we are used in Java. A Kotlin interface method can have a default implementation. Unlike Java 8, which requires the  default  keyword, Kotlin has no special annotation for such methods: you just provide a method body. Example:

interface Person {
   fun canWork():String = "I can unknown!"

Kotlin interfaces can have properties but these need to be abstract or to provide accessor implementations. Example:

interface Person {
      var Name:String //abstract
      var Gender:String // abstract
      fun canWork():String = "I can unknown!"

We can implement interfaces in a class look like this:

class Student:Person
    override var Name:String=""
        get() = field.toUpperCase()
            field="I am $value"
    override var Gender:String =""
    var StudentID:String = ""
    var University:String=""
    override fun canWork(): String {
        return "$Name .I am learning at $University. My ID is $StudentID and my gender is $Gender \n"

Kotlin doesn’t support multiple inheritances, however, the same thing can be achieved by implementing more than two interfaces at a time.

Data Classes

Like most other aspects of Kotlin, data classes aim to reduce the amount of boilerplate code you write in your project. Data classes provide compiler-generated  equals() ,  hashCode() ,  toString() ,  copy() , and other methods. An example of a normal class:

class Person {
        var Name: String = ""

We create an object from the  Person  class:

val p = Person()
println( p.toString())

The result can look like this:


Now, we change the  Person  class to become a data class by using  data  keyword as follows:

data class Person(var Name:String = "")

We create an object from the Person class again:

val p = Person(Name="Minh")
println( p.toString())

The result can look like this:


If we declare some properties inside  Person  class body as follows:

data class Person1(var Name:String =""){
     var Gender:String=""
     var Address:String=""   

Creating an object

val p = Person(Name="Minh")
p.Gender ="Male"
p.Address="New York"
println( p.toString())

The result also looks like this:


This is because the compiler only uses the properties defined inside the primary constructor for  toString() ,  equals() ,  hashCode() , and copy() implementations.

We also can use the copy() method copy an object altering some of its properties. An example:

val person = Person(Name="Minh", Gender="Male",Address = "NewYork")
val otherperson = person.copy(Address = "Chicago")
println( p.toString()) // The result: Person(Name=Minh,Gender=Male,Address=Chicago)

Nested and Inner Classes

In Kotlin, classes can be nested in other classes:

class FlyAnimal {
    class Bird {

A class may be marked as  inner  to be able to access members of outer class. Inner classes carry a reference to an object of an outer class:

class FlyAnimal {
    private val wings: Int = 2
    inner class Bird {
        var birdWings = wings
println (FlyAnimal().Bird().birdWings.toString()) // 2

Sealed Classes

When you evaluate an expression using the  when  construct, the Kotlin compiler forces you to check for the default option. Example:

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else -> throw IllegalArgumentException("Unknown expression")

If you add a new subclass, the compiler won’t detect that something has changed. If you forget to add a new branch, the default one will be chosen, which can lead to subtle bugs. Kotlin provides a solution to this problem: : sealed classes. Let’s look at the following example:

sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
fun eval(e: Expr): Int =
when (e) {
is Expr.Num -> e.value
is Expr.Sum -> eval(e.right) + eval(e.left)

If you handle all subclasses of a sealed class in a when statement, you don’t need to provide the default branch.

An Android Application

In this application, I created an UI as follows:

Image title

We can input the first value, the second value, and choose an operator as follows:

Image title

Click the  CALCULATE  button, the result can look like this:

Image title

Some controls are used in this application:


ID attribute

Text attribute



























(You can see source code of activity_main.xml and strings.xml files here)

In the MainActivity.kt, the first, I created the sealed class named Expr and its subclasses:

sealed class Expr {
    class Num(val value: Double) : Expr()
    class Add(val left: Expr, val right: Expr) : Expr()
    class Sub(val left: Expr, val right: Expr) : Expr()
    class Mul(val left: Expr, val right: Expr) : Expr()
    class Div(val left: Expr, val right: Expr) : Expr()

In MainActivity class, I created the  eval  function:

fun eval(e: Expr): Double =
            when (e) {
                    is Expr.Num -> e.value
                    is Expr.Add -> eval(e.left) + eval(e.right)
                    is Expr.Sub -> eval(e.left) - eval(e.right)
                    is Expr.Mul -> eval(e.left) * eval(e.right)
                    is Expr.Div -> eval(e.left) / eval(e.right)

In OnClickListener, I got some inputs, assigned them to variables, and checked if a string is numeric or not using regular expressions (regex):

var numeric = true
str1 = value1.text.toString()
str2 = value2.text.toString()
//Check if a string is numeric or not using regular expressions (regex)
numeric = str1.matches("-?\\d+(\\.\\d+)?".toRegex()) && str2.matches("-?\\d+(\\.\\d+)?".toRegex())
        Val1 = value1.text.toString().toDouble()
        Val2 = value2.text.toString().toDouble()
        Val1 = 0.0
        Val2 = 0.0

The finally, I wrote some code:

// choose an operator
     Result = eval(Expr.Add(Expr.Num(Val1), Expr.Num(Val2)))
     Result = eval(Expr.Sub(Expr.Num(Val1), Expr.Num(Val2)))
     Result = eval(Expr.Mul(Expr.Num(Val1), Expr.Num(Val2)))
     Result = eval(Expr.Div(Expr.Num(Val1), Expr.Num(Val2)))
// display result
ResultDisplay = String.format("%.1f", Result)

I also didn’t forget to set  Click  event for the  CALCULATE  button:

val buttonClickListener = View.OnClickListener { view ->

Run application again:

Image title

You input texts for the first value and second value as follows:

Image title

Choose an operator and click the  CALCULATE  button, the result looks like this:

Image title


You can download my source here and I hope you have a great experience.