Introduction


Kotlin is a new generation language officially for Android developement. Well --- we are taking about the sealed classes. According to official docs "Sealed classes are used for representing restricted class hierarchies wherein the object or the value can have value only among one of the types, thus fixing your type hierarchies. Sealed classes are commonly used in cases, where you know what a given value to be only among a given set of options".

As the name implies, the sealed classes are restricted classes or bound class heirarchies. Sealed classes ensure type-safety by restricting the types to be matched at compile-time rather than at runtime.

How to define a Sealed Class?

  • By default a sealed class is abstract, therefore it cannot be instantiated.
  • Constructor by default is private.
  • To define a sealed class, just precede the class modifier with the sealed keyword.
A typical structure of sealed class is as follows:
  1. sealed class Demo
  2. fun main(args: Array)
  3. {
  4. var d = Demo() //compiler error Demo can not instantiated
  5. }
Let's have a look at the complete structure with some methods in it.
  1. sealed class Demo {
  2. class A : Demo() {
  3. fun display()
  4. {
  5. println("Subclass A of sealed class Demo")
  6. }
  7. }
  8. class B : Demo() {
  9. fun display()
  10. {
  11. println("Subclass B of sealed class Demo")
  12. }
  13. }
  14. }
  15. fun main()
  16. {
  17. val obj = Demo.B()
  18. obj.display()
  19. val obj1 = Demo.A()
  20. obj1.display()
  21. }
Output

Subclass B of sealed class Demo
Subclass A of sealed class Demo

Difference between Enums and Sealed classes

Sealed classes in Kotlin can be thought of as enums on steroids. Sealed classes allow us to create instances with different types, unlike Enums which restrict us to use the same type for all enum constants.

The following is not possible in enum classes.
  1. enum class Months(string: String){
  2. January("Jan"), February(2),
  3. }
The enums can take single types of constants. This situation is overcome by Sealed classes which holds the different type of constants.
  1. sealed class Months {
  2. class January(var shortHand: String) : Months()
  3. class February(var number: Int) : Months()
  4. class March(var shortHand: String, var number: Int) : Months()
  5. }

Sealed classes with when

Sealed classes are widely used with the when statements as the choices become the subclasses and their type acts as a case.
Let's see how when is used with sealed classes. We have a sealed class with named as shape with three different subclasses. Now this subclass became the choice in when.
Example 1
  1. sealed class Shape{
  2. class Circle(var radius: Float): Shape()
  3. class Square(var length: Int): Shape()
  4. class Rectangle(var length: Int, var breadth: Int): Shape()
  5. }
Now convert the above code with "when".
  1. fun eval(e: Shape) =
  2. when (e) {
  3. is Shape.Circle -> println("Circle area is ${3.14*e.radius*e.radius}")
  4. is Shape.Square -> println("Square area is ${e.length*e.length}")
  5. is Shape.Rectangle -> println("Rectagle area is ${e.length*e.breadth}")
  6. }
Let's call the above method in the main function.
  1. fun main(args: Array<String>) {
  2. var circle = Shape.Circle(4.5f)
  3. var square = Shape.Square(4)
  4. var rectangle = Shape.Rectangle(4,5)
  5. eval(circle)
  6. eval(square)
  7. eval(rectangle)
  8. //eval(x) //compile-time error.
  9. }
Output
Circle area is 63.585
Square area is 16
Rectangle area is 20
Example 2
Let's see another example to demonstrate when statment with sealed class.
  1. // A sealed class with a string property
  2. sealed class Fruit
  3. (val x: String)
  4. {
  5. // Two subclasses of sealed class defined within
  6. class Apple : Fruit("Apple")
  7. class Mango : Fruit("Mango")
  8. }
  9. // A subclass defined outside the sealed class
  10. class Pomegranate: Fruit("Pomegranate")
  11. // A function to take in an object of type Fruit
  12. // And to display an appropriate message depending on the type of Fruit
  13. fun display(fruit: Fruit){
  14. when(fruit)
  15. {
  16. is Fruit.Apple -> println("${fruit.x} is good for iron")
  17. is Fruit.Mango -> println("${fruit.x} is delicious")
  18. is Pomegranate -> println("${fruit.x} is good for vitamin d")
  19. }
  20. }
  21. fun main()
  22. {
  23. // Objects of different subclasses created
  24. val obj = Fruit.Apple()
  25. val obj1 = Fruit.Mango()
  26. val obj2 = Pomegranate()
  27. // Function called with different objects
  28. display(obj)
  29. display(obj1)
  30. display(obj2)
  31. }
Output
Apple is good for iron.
Mango is delicious.
Pomegranate is good for vitamin d.