Kotlin From Learning to Android Chapter 11 Enumeration Classes, Nested Classes and Sealed Classes

1. Enumeration class

The most basic use of enumeration classes is to implement type-safe enumerations:

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

Each enumeration constant is an object, and the enumeration constants are separated by ",".

initialization

Since each enum is an instance of the enum class, they can be initialized:

enum class Color(val rgb: Int) {
        RED(0xFF0000),
        GREEN(0x00FF00),
        BLUE(0x0000FF)
}

anonymous class

Enum constants can also declare their own anonymous classes:

enum class ProtocolState {
    WAITING {
        override fun signal() = TALKING
    },

    TALKING {
        override fun signal() = WAITING
    };// 枚举类中定义了成员(下面的 signal() 函数),所以要用分号分开

    abstract fun signal(): ProtocolState
}

The anonymous class of the enumeration constant can not only define its own function, but also override the function of the enumeration class. Note : If the enum class defines any members, you must use a semicolon to separate the enum constants and members.

Use of enumeration constants

Similar to Java, enumeration classes in Kotlin also have methods to list defined enumeration constants and get an enumeration constant by the name of the enumeration constant. For example (assuming the name of the enum class is EnumClass):

EnumClass.valueOf(value: String): EnumClass
EnumClass.values(): Array<EnumClass>

If the enumeration constant does not match the value of the valueOf() method parameter, an IllegalArgumentException will be thrown.

Starting from Kotlin 1.1, you can use the enumValues() and enumValueOf() functions to access enumeration constants in enumeration classes in a generic way:

enum class RGB { RED, GREEN, BLUE }

inline fun <reified T : Enum<T>> printAllValues() {
    print(enumValues<T>().joinToString { it.name })
}

printAllValues<RGB>() // RED, GREEN, BLUE

Each enumeration constant has name and ordinal attributes, respectively marking the name and order of this constant in the enumeration class:

println(RGB.BLUE.name)          // BLUE
println(RGB.BLUE.ordinal)       // 2

Enumeration constants also implement the Comparable interface, and their natural order is the order defined in the enumeration class.


2. Nested classes

Classes can nest other classes:

class Outer {
    private val bar: Int = 1
    class Nested {
        fun foo() = 2
    }
}

val demo = Outer.Nested().foo() // == 2

inner class

An inner class marked inner can access members of the outer class. The inner class has a reference to an object of the outer class:

class Outer {
    private val bar: Int = 1
    inner class Inner {
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo() // == 1

anonymous inner class

Anonymous inner classes are instantiated via object expressions :

window.addMouseListener(object: MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ...
    }

    override fun mouseEntered(e: MouseEvent) {
        // ...
    }
})

If this anonymous object is an instantiation of a java interface, and this interface has only one abstract method, then you can directly use the interface name lambda expression to instantiate:

val listener = ActionListener { println("clicked") }

3. Sealing

Sealed classes are used to represent restricted class hierarchies, i.e. a value can have one type from a limited set, but not any other type. In a sense, they are extensions of enumeration classes: the set of values ​​of enumeration types is also restricted, but each enumeration constant only exists as a single instance, whereas subclasses of sealed classes can contain multiple instances and contain state.
To declare a sealed class, you add the sealed modifier before the class name. A sealed class can have subclasses, but all classes must be declared in the same file as the sealed class itself. (Before Kotlin 1.1, the rules were stricter: classes had to be nested inside the declaration of a sealed class).

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

The above example uses another new feature of Kotlin 1.1: data classes extend the functionality of other classes, including sealed classes.

Note : Classes that subclass (indirectly inherit) a sealed class can be placed anywhere, not necessarily in the same file.

// file01.kt
fun main(args: Array<String>) {

    fun eval(expr: Expr): Double = when(expr) {
        is Const -> expr.number
        is Sum -> eval(expr.e1) + eval(expr.e2)
        is TestN -> 20e0
        NotANumber -> Double.NaN
        // 由于覆盖了所有的可能性,所以不需要 else 分支
    }

    print(eval(TestA()))                // 20.0
}
sealed class Expr
data class Const(open val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
open class TestN : Expr()

// file02.kt
class TestA() : TestN()

The key benefit of using a sealed class is that when you use a when expression, you don't need to add an else clause to the statement if you can verify that the statement covers all cases.

Guess you like

Origin blog.csdn.net/niuzhucedenglu/article/details/73196388