Kotlin is a modern programming language that compiles to Java bytecode. It is free and open source, and promises to make coding for Android even more fun.

In the previous article, you learned more about Kotlin properties such as late-initialization, extension, and inline properties. Not only that, you also learned about advanced classes such as data, enum, nested, and sealed classes in Kotlin.

In this post, you'll continue to learn about object-oriented programming in Kotlin by learning about abstract classes, interfaces, and inheritance. For a bonus, you'll also learn about type aliases.

1. Abstract Classes

Kotlin supports abstract classes—just like Java, these are classes which you never intend to create objects from. An abstract class is incomplete or useless without some concrete (non-abstract) subclasses, from which you can instantiate objects. A concrete subclass of an abstract class implements all the methods and properties defined in the abstract class—otherwise that subclass is also an abstract class!

We create an abstract class with the abstract modifier (similar to Java).

Here we created the non-abstract function fullName() in an abstract class Employee. Concrete classes (subclasses of the abstract class) can override an abstract method's default implementation—but only if the method has the open modifier specified (you will learn more about this shortly).

Make sure you use this functionality wisely! Be aware that we can't do the reverse—override a var property with val.

2. Interfaces

An interface is simply a collection of related methods that typically enable you to tell objects what to do and also how to do it by default. (Default methods in interfaces are a new feature added to Java 8.) In other words, an interface is a contract that implementing classes must abide by.

An interface is defined using the interface keyword in Kotlin (similar to Java).

In the code above, we've declared a StudentRepository interface. This interface contains two abstract methods: getById() and getResultsById(). Note that including the abstract keyword is redundant in an interface method because they are already abstract implicitly.

An interface is useless without one or more implementers—so let's create a class that will implement this interface.

As stated, a Kotlin interface can have properties—but note that it can't maintain state. (However, remember abstract classes can maintain state.) So the following interface definition with a property declaration will work.

The compiler is confused about calling the super.funD() method because the two interfaces that the class implements have the same method signature.

To solve this problem, we wrap the interface name for which we want to call the method in angle brackets <InterfaceName>. (IntelliJ IDEA or Android Studio will give you a hint about solving this issue when it crops up.)

Here we are going to call the funD() method of InterfaceA. Problem solved!

3. Inheritance

A new class (subclass) is created by acquiring an existing class's (superclass) members and perhaps redefining their default implementation. This mechanism is known as inheritance in object-oriented programming (OOP). One of the things that make Kotlin so awesome is that it encompasses both the OOP and functional programming paradigms—all in one language.

The base class for all classes in Kotlin is Any.

class Person : Any {
}

The Any type is equivalent to the Object type we have in Java.

public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}

The Any type contains the following members: equals(), hashcode(), and also toString() methods (similar to Java).

Our classes don't need to explicitly extend this type. If you don't explicitly specify which class a new class extends, the class extends Any implicitly. For this reason, you typically don't need to include : Any in your code—we do so in the code above for demonstration purposes.

Let's now look into creating classes in Kotlin with inheritance in mind.

class Student {
}
class GraduateStudent : Student() {
}

In the code above, the GraduateStudent class extends the superclass Student. But this code won't compile. Why? Because classes and methods are final by default in Kotlin. In other words, they cannot be extended by default—unlike in Java where classes and methods are open by default.

Software engineering best practice recommends that you to begin making your classes and methods final by default—i.e. if they aren't specifically intended to be redefined or overridden in subclasses. The Kotlin team (JetBrains) applied this coding philosophy and many more development best practices in developing this modern language.

For us to allow subclasses to be created from a superclass, we have to explicitly mark the superclass with the open modifier. This modifier also applies to any superclass property or method that should be overridden by subclasses.

open class Student {
}

We simply put the open modifier before the class keyword. We have now instructed the compiler to allow our Student class to be open for extension.

As stated earlier, members of a Kotlin class are also final by default.

Here, the open schoolFees function from the superclass Student is overridden by the GraduateStudent class—by adding the override modifier before the fun keyword. Note that if you override a member of a superclass or interface, the overriding member will also be open by default, as in the example below:

Even though we didn't mark the schoolFees() method in the GraduateStudent class with the open modifier, we can still override it—as we did in the ComputerScienceStudent class. For us to prevent this, we have to mark the overriding member as final.

Remember that we can add new functionality to a class—even if it's final—by the use of extension functions in Kotlin. For a refresher on extension functions, check out my Advanced Functions in Kotlin post. Also, if you need a refresher on how to give even a final class new properties without inheriting from it, read the section on extension Properties in my Advanced Properties and Classes post.

4. Bonus: Type Alias

In the class above, we can assign the String and Int types for the Person properties aliases using the typealias modifier in Kotlin. This modifier is used to create an alias of any type in Kotlin—including the ones you have created.

As you can see, we have created an alias Name and Age for both the String and Int types respectively. We have now replaced the firstName and lastName property type to our alias Name—and also Int type to Age alias. Note that we didn't create any new types—we instead created an alias for the types.

These can be handy when you want to provide a better meaning or semantic to types in your Kotlin codebase. So use them wisely!

Conclusion

In this tutorial, you learned more about object-oriented programming in Kotlin. We covered the following:

abstract classes

interfaces

inheritance

type alias

If you have been learning Kotlin through our Kotlin From Scratch series, make sure you have been typing the code you see and running it on your IDE. One great tip to really grasp a new programming language (or any programming concept) you're learning is to make sure you don't just only read the learning resource or guide, but also type the actual code and run it!

In the next tutorial in the Kotlin From Scratch series, you'll be introduced to exception handling in Kotlin. See you soon!

To learn more about the Kotlin language, I recommend visiting the Kotlin documentation. Or check out some of our other Android app development posts here on Envato Tuts!