Skip to content
Table of contents
Downcasting

Downcasting

1 min read #kotlin

Downcasting is to discover the specific type of a previously upcast object. Upcast is always safe because the base class cannot have a bigger interface than the derived class. Every base class member is guaranteed to exist and is therefore safe to call. Although object-oriented programming is primarily focused on upcasting, there are situations where downcasting can be a useful and expedient approach.

Downcasting happens at runtime, and is also called run-time identification (RTII).

As we can see, we cannot access b1.g() and b2.h() since both b1 and b2 are upcast to base.

Smart Cast

Smart Cast is automatic downcast. This is keyword checks whether an object is a particular type. Any code within the scope of that check assumes that it is that type:

fun main() {
  val b1: Base = Derived1()
  if (b1 is Derived1) // scope within the check
    b1.g()
}
kotlin

The as keyword

The as keyword forcefully casts a general type to a specific type. A failing as cast throws a ClassCastException. A plain as is called an unsafe cast.

When a safe cast as? fails, it doesn’t throw an exception, but instead returns null.

Discovering Types in Lists

val group: List<Creature> = listOf(
  Dog(), Human(), Dog()
)

val dog = group.find { it is Dog } as Dog?
dog?.bark()
kotlin

The code above can be written using filterIsInstance(), which produces all elements of a specific type.

val dogs : List<Human> = group.filterIsInstance<Human>()
kotlin

filterIsInstance is more readable than using filter(). The difference between filter() and the filterIsInstance() is the return values. filter returns a List of Creature whereas filterIsInstance returns the target.