First, we have an abstract class. Remember that our abstract functions/properties MUST be over-ridden.
1 2 3 4 5 6 7 |
// create abstract class // over-riding properties and functions is a MUST abstract class Course(private val topic: String, private val price: Double) { open fun learn() { println("For the price of $price, you can learn $topic") } } |
In order to use this abstract class, we can use an open class. An open class means it can be extended. It can also extend from abstract class Course. When we extend Course, we initialize its properties. We’re not happy with its default learn function, so we override it and implement it ourselves.
open in abstract means it is over-ridable. If there is no open keyword, then the default keyword ‘final’ applies.
As you can see, when we instantiate KotlinCourse, we execute learn function and see that it calls KotlinCourse’ learn function.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// over-riding properties and functions are OPTIONAL // We CAN instantiate open classes // we extend Course, which means we must over-ride learn open class KotlinCourse: Course("Kotlin", 999.99) { override fun learn() { println("Kotlin Course: You'll learn lots of awesome programming skills with KOTLIN!!!") } } fun main(args: Array<String>) { val course = KotlinCourse() course.learn() } |
What we have a specialized class SpecializedKotlinClass that extends KotlineCourse?
By default, we can override the learn function in KotlinCourse. If we DO NOT override it, it will simply call KotlinCourse’s learn function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
abstract class Course(private val topic: String, private val price: Double) { open fun learn() { println("For the price of $price, you can learn $topic") } } open class KotlinCourse: Course("Kotlin", 999.99) { override fun learn() { println("Kotlin Course: You'll learn lots of awesome programming skills with KOTLIN!!!") } } class SpecializedKotlinClass: KotlinCourse() { override fun learn() { println("Welcome to a Specialized version of our Kotlin Class!!!") } } fun main(args: Array<String>) { val course = KotlinCourse() course.learn() } |
However, say we don’t want people to over-ride KotlinCourse’s function. Any class that extends KotlinCourse MUST USE its learn function.
In order to prevent others to -override KotlinCourse’ learn function, simply put final override fun.
Thus, this prevents SpecializedKotlinClass from overriding the learn function. Doing so would give you a compiler error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
abstract class Course(private val topic: String, private val price: Double) { open fun learn() { println("For the price of $price, you can learn $topic") } } open class KotlinCourse: Course("Kotlin", 999.99) { final override fun learn() { println("Kotlin Course: You'll learn lots of awesome programming skills with KOTLIN!!!") } } class SpecializedKotlinClass: KotlinCourse() { override fun learn() { println("Welcome to a Specialized version of our Kotlin Class!!!") } } fun main(args: Array<String>) { val course = SpecializedKotlinClass() course.learn() } |
Multiple Super Types
Say we create another interface with a learn function:
And we extend both from abstract and interface…where both have function learn. When you use super, the compiler will be confused which super type you are referring to. In this case, we can use the bracket and the super type name to designate whether you want to use the interface or the abstract one.
1 2 3 4 5 6 7 8 |
open class KotlinCourse: Course("Kotlin", 999.99), Learnable { final override fun learn() { super<Learnable>.learn() super<Course>.learn() println("finised learning") } } |