Introduction to Kotlin Object-Oriented Programming

May 22 2024 · Kotlin 1.9.21, Android 14, Kotlin Playground & Android Studio Hedgehog | 2023.1.1

Lesson 03: Inheritance & Polymorphism

Demo

Episode complete

Play next episode

Next
Transcript

In this demo, you’ll create a subclass of MuseumObject. You’ll move primaryImageSmall to this subclass, then override the showImage() method.

Open the starter project for this lesson in Android Studio OR simply copy and paste the content of the MainActivity.kt file to stay updated.

You’ll start by creating a PublicDomainObject subclass of MuseumObject. The primaryImageSmall property is a String, and it’s non-empty only for public domain art objects, so it makes sense to remove this property from MuseumObject and have it only in PublicDomainObject.

In MuseumObject, comment out or delete the primaryImageSmall line:

//  val primaryImageSmall: String,

Scroll down to where a MuseumObject is initialized. You can see we have an error, and this is simply because that property doesn’t exist in that class anymore.

To fix the error, comment out or delete this line:

primaryImageSmall: "https://images.metmuseum.org/CRDImages/ep/original/DT1567.jpg",

Then, scroll back to showImage() and modify it to always open the WebViewComposable like so:

fun showImage() {
  return WebViewComposable(url = objectURL) // Updated code
}

With this, every instance of MuseumObject shows its image by loading its page in the in-app browser.

Scroll down to the AsyncImage in the MuseumObjectComposable.

There’s another error in MuseumObjectComposable, which you’ll fix after creating your subclass.

Let’s do that now.

Enter the following code:

class PublicDomainObject(
  objectID: Int,
  title: String,
  objectURL: String,
  creditLine: String,
  isPublicDomain: Boolean,
) : MuseumObject(objectID, title, objectURL, creditLine, isPublicDomain) {

}

This is how you subclass MuseumObject. You create a primary constructor to match all the inherited properties of the parent class. You also make sure you add their types. After the constructor, you then add a colon and call the parent class, which in this case is the MuseumObject. Then, you pass its parameters in its constructor. The colon, in this case, shows that the PublicDomainObject class extends the MuseumObject class. In other words, PublicDomainObject is a MuseumObject. It inherits all the properties and methods of MuseumObject, and you can add more properties and methods or override MuseumObject methods and redefine them to do something different.

You have an error on MuseumObject, and this is simply because you’ve not marked it open for inheritance.

So go ahead and add the open keyword to the MuseumObject definition:

open class MuseumObject

Next, add the property you removed from MuseumObject, which is primaryImageSmall:

val primaryImageSmall: String,

Then, set the value of isPublicDomain to true:

isPublicDomain: Boolean = true,

You do this because you want primaryImageSmall to exist only when you’re viewing a PublicDomainObject, and that’s why you give it a default value.

Let’s override showImage() in the PublicDomainObject class.

First, start by marking it open for inheritance in the parent class:

open fun showImage() {
  //...
}

Then override it in the PublicDomainObject class like so:

@SuppressLint("ComposableNaming")
@Composable
override fun showImage() {
  return MuseumObjectComposable(obj = this)
}

Now, every instance of PublicDomainObject shows its image in MuseumObjectComposable. Do note that the this keyword here is simply used to refer to the instance of a class whose function we’re running. In this case, this as used here is referring to an instance of PublicDomainObject.

Scroll down to MuseumObjectComposable and change its parameter to be a PublicDomainObject:

fun MuseumObjectComposable(obj: PublicDomainObject) {
  //...
}

If you scroll down to the error you got previously, you’ll see that it’s gone, and that’s because the PublicDomainObject has the primaryImageSmall as one of its properties, so everything is fine now.

Next, create an instance of the new subclass. Scroll back up to where a MuseumObject was initialized.

Copy-paste and edit the MuseumObject declaration like so:

val obj_pd =
  PublicDomainObject(
    objectID = 436535,
    title = "Wheat Field with Cypresses",
    objectURL = "https://www.metmuseum.org/art/collection/search/436535",
    primaryImageSmall = "https://images.metmuseum.org/CRDImages/ep/original/DT1567.jpg",
    creditLine = "Purchase, The Annenberg Foundation Gift, 1993",
  )

Remember, you set a default value for isPublicDomain to true, so you don’t have to include it here.

Now, you’ve created the same art object as a MuseumObject and as a PublicDomainObject.

The showImage() method with the MuseumObject instance has been called in the main activity of the starter project, so go ahead and run your code.

It displays the art object’s web page because a MuseumObject always calls WebViewComposable.

Comment out obj.showImage() and call showImage() with your PublicDomainObject:

obj_pd.showImage()

As expected, you get the MuseumObjectComposable because that’s what the PublicDomainObject method calls.

This is an example of polymorphism because the showImage method exists in different forms depending on the object calling it. You didn’t have to create two methods with different names. Instead, the method to be executed is determined at runtime. Method overriding is also known as runtime or dynamic polymorphism.

If you changed the number, order or type of parameters when defining the method with the same name, that would be static or compile-time polymorphism, which is also known as method overloading. You saw that from the first lesson when you worked with the Driving class.

That ends this demo. Continue with the lesson for a summary.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion