- Published on
OOP Mastery – Theory 03: Class and Interface Types in Kotlin
- Authors
- Name
- Dan Tech
- @dan_0xff
Kotlin is a modern programming language that offers many types of Classes and Interfaces to support your programming. This article gives you a specific look at each type of Class and Interface in the Kotlin language to understand and be able to use them effectively in the future.
Kotlin Class
This is the basic form of Kotlin for defining a class. The syntax is very simple
class MyClass {
// Define your members
}
class Empty // declares a class with nothing inside
Constructor
Kotlin supports multiple constructor approaches for a class
class MyClass(val intProp: Int) {
fun samplePublicFunction() {
println("Hello world!")
}
}
class MyAnotherClass constructor(val intProp: Int) {
fun anotherPublicFunction() {
println("Hello world 2!")
}
}
class MyClassWithMultipleConstructor {
var stringProp: String = ""
var intProp: Int = 0
constructor(intProp: Int) {
this.intProp = intProp
}
constructor(stringProp: String) {
this.stringProp = stringProp
}
}
Note: Default Access Modifier in Kotlin is Public
Object creation
Unlike C, C++ where object initialization must go through a Pointer, Kotlin and some other modern languages have a very simple way to initialize objects.
val a = MyClass(1)
a.samplePublicFunction()
var b = MyAnotherClass(0)
b.anotherPublicFunction()
Destructor
Kotlin's memory allocation and management mechanism uses GC (Garbage Collector) which is different from the C++ language - I won't go too deep to avoid rambling.
Because it uses GC, in Kotlin we don't need to actively delete the objects that have been created. GC will automatically detect and delete objects that have been created when they are no longer in use.
Object comparison
Kotlin has built-in support for 2 comparison operators, == and ===
- == Compares values, compares content
- === Compares the address (reference) that the variable points to
Classes in Kotlin, if declared using the default syntax class Myclass
, will not be equal in comparisons using the == or === operators, even if the elements inside them are equal.
class MyClass(val name: String)
fun main() {
val myClass1 = MyClass("Hello")
val myClass2 = MyClass("Hello")
println(myClass2 == myClass1) // false
println(myClass2 === myClass1) // false
}
How can we make them equal in the case where the properties inside are equal?
The solution is to override the equals and hashCode functions for easy comparison.
class MyClass(val name: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other !is MyClass) return false
return name == other.name
}
override fun hashCode(): Int {
return name.hashCode()
}
}
fun main() {
val myClass1 = MyClass("Hello")
val myClass2 = MyClass("Hello")
println(myClass2 == myClass1) // false
println(myClass2 === myClass1) // false
println(myClass1.hashCode() == myClass2.hashCode()) // false
}
Because of this inconvenience, Kotlin created data class
, which you will learn about in the next section.
Kotlin Interface
Interface - many sources translate as giao diện (interface)
What's special about Interfaces in Kotlin is that they can contain pre-defined functions, or not, and contain variables. Interfaces in Kotlin are much more versatile and convenient than in C++.
interface MyUserInterface {
var name: String
var age: Int
fun myFunction() {
println("Hello From Interface User")
}
}
class ProUser(
override var name: String,
override var age: Int
) : MyUserInterface {
override fun myFunction() {
println("Hello")
}
}
fun main() {
val user: MyUserInterface = ProUser("Pro", 20)
println("User Info: ${user.name} ${user.age}")
println("User Info: $user") // only prints the address of the variable, not the value of the content
}
In the example above, you cannot print the information of the user object. That is why Kotlin created Data Class.
Kotlin Data Class
Kotlin has the concept of Data Class used to refer to Classes that contain data - only Data & no Logic.
How to declare and use data class
data class MyUserDataClass(val name: String, var age: Int)
// Data class can contain member variables that are var or val
fun main() {
val myUserDataObject = MyUserDataClass("John", 25)
val myUserDataObject2 = MyUserDataClass("John", 25)
println("User Name: $myUserDataObject")
println("myUserDataObject == myUserDataObject2: ${myUserDataObject == myUserDataObject2}")
println("myUserDataObject.hashCode == myUserDataObject2.hashCode: ${myUserDataObject.hashCode() == myUserDataObject2.hashCode()}")
println("myUserDataObject === myUserDataObject2: ${myUserDataObject === myUserDataObject2}")
}
Characteristics of data class in Kotlin
- The println function will print the content of the object created by the data class instead of its address.
- == comparison between 2 different objects created by data class will compare the content of each object. If they have the same value, TRUE will be returned
- === comparison between 2 different objects created by data class will return FALSE. Because they belong to 2 different memory regions.
Kotlin Enum Class
Enum is not a new concept in modern programming languages. Enum is used in logic for classification because of its convenience.
In Kotlin, enum does not have a separate declaration method. To declare an enum, we must declare it through enum class
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
enum class UserTier {
FREE, PREMIUM
}
Enum class in Kotlin is very versatile when you can define additional data attached to each enum type.
enum class MessageState(val value: String) {
FAILED("failed"),
SENDING("sending"),
RECEIVED("received"),
READ("read")
}
Programmers can access the values of the enum to manipulate according to the design of the software.
enum class MyUserEnum(val role: String) {
ADMIN("admin"),
USER("user"),
GUEST("guest")
}
fun main() {
MyUserEnum.entries.forEach {
println("string value: $it")
println("role of enum:" + it.role)
println("name of enum" + it.name)
println("ordinal of enum: " + it.ordinal)
println("---")
}
}
Kotlin Sealed Class, Interface
Sealed Class, Interface in Kotlin are created with the purpose of preventing inheritance from Class, Interface after the code has been compiled.
Sealed Class and Interface in Kotlin will prevent the inheritance of Sub Classes after they compiled.
Problem statement: Programmers of a library written in Kotlin do not want external source code to inherit their Classes and Interfaces for expansion and development. In this case, sealed will be the solution. The source code has the right to use it, if the library has an error, you have to wait for a new update from the library's Dev, you cannot arbitrarily expand or inherit the library's Classes and Interfaces for your own purposes.
Kotlin Object
Kotlin Object is the solution for the Singleton pattern in the Kotlin language.
In your application, there will be times when you need data that only has 1 unique Instance across the entire application. Kotlin Object will make that simpler.
object FilePathProvider {
val cachePath: String = "file://cache"
val diskPath: String = "file://disk"
}
Kotlin object provides a Thread-safe solution for the Singleton pattern. This means that in all cases the program always creates 1 and only 1 Instance of a Kotlin object.