5.1 Class construction

5.1.1 Simple definition of class

Let’s take a look at the MainActivity class we’ve seen many times in Android development. In Java code, this class is written as follows:

/ / Java
public class MainActivity extends AppCompatActivity{... }/ / kotlin writing

class MainActivity :AppCompatActivity(a){... }Copy the code

A brief comparison of the above code shows the following differences between Kotlin’s approach to class writing and Java’s: (1) Kotlin omitted the keyword public because it is open by default. (2) Kotlin uses the colon “:” instead of extends, which is a colon for inheritance. (3) When Kotlin inherited, the parent class was followed by parentheses “()”.

Next from the simple class definition, set a simple animal class code;

class Animal {
    // Class initialization
    init {
        println("Animal: It's an Animal.")}}Copy the code

The code for creating an instance of the Animal class externally looks like this:

    btn_simple_class.setOnClickListener {

            //var animal:Animal=Animal()
            // Since we already know that this is an instance of Animal by the constructor after the equals sign, we can declare the object without specifying its type

            var animal = Animal()
        }
Copy the code
  • Kotlin initializes the class by calling it init, rather than using the class name as a constructor name, as Java does
  • Kotlin uses the C-speech-like println method for printing logs instead of Java’s system.out.println
  • Kotlin omitted the keyword new when creating the instance

5.1.2 Class constructors

When we introduced functions in Chapter 4, we mentioned that Kotlin regarded functions as special variables, so classes are in some sense special functions. So the constructor’s input parameters have to be appended directly to the class name, whereas the init method simply represents the initialization action when creating an instance of the class. Here is the code for the class definition with the added input parameter:

/** * & If a function is a special variable, then a class is in some sense a special kind of function. For multiple constructors, Kotlin introduced the concept of primary constructors and secondary constructors. * &the argument following the name of the class is the entry argument to the main constructor, and the init method is the internal code of the main constructor. * &The secondary constructor is a member of the main constructor. If you declare an instance of the class using the secondary constructor, you can write the complete function expression directly inside the class. The primary constructor's init code is called first, followed by the secondary constructor's own code */
class AnimalMain constructor(context: Context.name: String) {
    init {
        Toast.makeText(context, "This is a $name", Toast.LENGTH_SHORT).show()
    }

    constructor(context: Context, name: String, sex: Int) : this(context, name) {
        var sexName: String = if (sex == 0) "Male" else "Mother"
        Toast.makeText(context, ${sexName} = ${sexName}, Toast.LENGTH_SHORT).show()
    }
}
Copy the code

Now if you want to declare an instance of the AnimalMain class, you can declare it either through the primary constructor or through the secondary constructor, as shown below:

   var count = 0
        btn_simple_class2.setOnClickListener {
            when (count % 2) {
                0- > {var animal = AnimalMain(this."Cat")}else- > {var animal = AnimalMain(this."Cat".0)
                }
            }
            count++
        }
Copy the code

Problems with secondary constructors: if an instance is declared with a secondary constructor, the toast of the init method is called

To address the pain point of secondary constructors calling primary constructors (the Toast method is executed twice), Kotlin sets the primary constructor optional. That is, a class can define several constructors inside the class, thus making them all secondary constructors, thus removing the primary constructor

class AnimalSeparate {
    constructor(context: Context, name: String) {
        Toast.makeText(context, "This is a $name", Toast.LENGTH_SHORT).show()
    }

    constructor(context: Context, name: String, sex: Int) {
        var sexName: String = if (sex == 0) "Male" else "Mother"
        Toast.makeText(context, ${sexName} = ${sexName}, Toast.LENGTH_SHORT).show()
    }
}
Copy the code

But then it’s no different from Java, right

5.1.3 Constructors with default arguments

Remember the default arguments for functions in Chapter 4? Class constructors can also add default arguments. Note that the two constructors of the AnimalSeparate class differ by only one input parameter, so it is perfectly possible to combine them into a single main constructor with default parameters. The new main constructor can take two arguments as well as three.

/** * & add annotations@JvmOverloadsKotlin can also use * & to add the main business need to add constructor */
class AnimalDefault(context: Context.name: String.sex: Int = 0) {
    init {
        println("8888")
        var sexName: String = if (sex == 0) "Male" else "Mother"
        Toast.makeText(context, ${sexName} = ${sexName}, Toast.LENGTH_SHORT).show()
    }
}
Copy the code

The specific external call code is as follows:

  btn_simple_class4.setOnClickListener {
            when (count % 2) {
                0- > {var animal = AnimalDefault(this."Cat")}else- > {var animal = AnimalDefault(this."Cat".1)
                }
            }
            count++
        }
Copy the code

Kotlin’s Java class is also available

/** * & add annotations@JvmOverloadsKotlin can also use * & to add the main business need to add constructor */
class AnimalDefault @JvmOverloads constructor(context: Context.name: String.sex: Int = 0) {
    init {
        println("8888")
        var sexName: String = if (sex == 0) "Male" else "Mother"
        Toast.makeText(context, ${sexName} = ${sexName}, Toast.LENGTH_SHORT).show()
    }
}
Copy the code

A member of class 5.2

5.2.1 Member Attributes

Since there is a one-to-one correspondence between attribute fields and constructor input parameters, there is a mechanism for the compiler to name and assign them automatically. Kotlin follows a similar design approach, and here’s how the Kotlin code works:


/** * & Member variables of a class can be declared in constructors preceded by the keyword "var" or" val" to declare a variable (immutable) parameter with the same name as the parameter * & If a field is not an attribute of the same name as the input parameter, you need to explicitly declare the attribute inside the class
class WildAnimal(var name: String.val sex: Int = 0) {}Copy the code

It turns out that Kotlin has drastically simplified the code, including: (1) redundant attribute declarations with the same name. (2) Redundant attribute assignment statements with the same name. (3) Redundant attribute acquisition and setting methods.

If a field is not an attribute of the same name as the input parameter, you need to explicitly declare the attribute field inside the class.

class WildAnimal(var name: String.val sex: Int = 0) {
    var sexName: String/ / Non-empty member attributes must be assigned at declaration time or in the constructor// The compiler says "Property must be initialized or be abstract"
    init {
        sexName = if (sex == 0) "Male" else "Mother"}}Copy the code

Use:

btn_simple_class5.setOnClickListener {
            var animal = when (count % 2) {
                0 -> WildAnimal("Cat")
                else -> WildAnimal("Cat".1)
            }
            count++
            btn_simple_class5.text = ${animal.sexName} = ${animal.sexName}
        }
Copy the code

5.2.2 Membership method

The process of defining a member method inside a class is similar to the ordinary function definition mentioned in Chapter 4. For details, see 4.1 Basic Usage of Functions and 4.2 Changes in input parameters, which are not described here.

class WildAnimalFunction(var name: String.val sex: Int = 0) {
    var sexName: String

    init {
        sexName = if (sex == 0) "Male" else "Mother"
    }

    fun getDesc(tag: String) :String {

        return ${sexName} ${sexName} ${sexName}}}Copy the code

Call:

btn_simple_class6.setOnClickListener {
            var animal = when (count % 2) {
                0 -> WildAnimalFunction("Cat")
                else -> WildAnimalFunction("Cat".1)
            }
            count++
            btn_simple_class6.text = animal.getDesc("动物园")}Copy the code

5.2.3 Associated Objects

Kotlin’s approach to member attributes and methods was described earlier. To access either a member attribute or a member method, you must first declare the object of the class and then access the members of the class through the object. But Java also has static members. Static members are decorated with the keyword static, and are externally defined by the class name. Access static members (including static properties and methods) in the form of static member names.

However, Kotlin has removed the keyword static, so that static members cannot be declared directly. To compensate for this lack of functionality, Kotlin introduced the concept of companion objects.

Here is an example of code that extends the class definition with associated objects:

class WildAnimalCompanion(var name: String.val sex: Int = 0) {
    var sexName: String

    init {
        sexName = if (sex == 0) "Male" else "Mother"
    }

    fun getDesc(tag: String) :String {
        return ${sexName} = ${sexName}
    }
    Static {...} static{...} static{...} static{... } code block

    companion object WildAnimal {
        fun judgeSex(sexName: String): Int {
            var sex: Int = when (sexName) {
                "Male"."Male" -> 0
                "Mother"."Female" -> 1
                else -> -1
            }
            return sex
        }
    }
}
Copy the code

Outside calls


        val sexArray: Array<String> = arrayOf("Male"."Mother"."Male"."Female")
        btn_simple_class7.setOnClickListener {
            var sexName: String = sexArray[count++ % 4]
            // The WildAnimal name of the accompanying object can be omitted
/ / btn_simple_class7. Text = "${sexName} corresponding type is ${WildAnimalCompanion. WildAnimal. JudgeSex (sexName)}"
            btn_simple_class7.text = "$sexName corresponding type is ${WildAnimalCompanion. JudgeSex (sexName)}"
        }
Copy the code

5.2.4 Static Properties

If a companion object can implement static functions, it can also implement static properties by adding a few field definitions inside the companion object.

class WildAnimalConstant(var name: String.val sex: Int = MALE) {
    var sexName: String

    init {
        sexName = if (sex == MALE) "Male" else "Mother"
    }

    fun getDesc(tag: String) :String {
        return ${sexName} = ${sexName}
    }

    companion object WildAnimal {
        // Static constants cannot be changed, so use the keyword val
        val MALE = 0
        val FEMALE = 1
        val UNKNOW = -1
        fun judgeSex(sexName: String): Int {
            var sex: Int = when (sexName) {
                "Male"."Male" -> MALE
                "Mother"."Female" -> FEMALE
                else -> -1
            }
            return sex
        }
    }
}
Copy the code

As you can see from the code above, the value 0 for gender is replaced by MALE, and the value 1 is replaced by FEMALE, thus increasing. Code readability. If you want to externally judge the sex of an animal, you can use the expression to see from the above code that the value 0 representing the sex is replaced by MALE, and the value 1 is replaced by FEMALE, thus improving. Code readability. External to the judgement of animal sex, you can use the expression WildAnimalConstant. MALE MALE, use WildAnimalConstant. FEMALE FEMALE.

5.3 Class inheritance

5.3.1 Open modifiers

Kotlin defaults that every class cannot be inherited (equivalent to Java classes being finial modified). To make a class a base class, you need to expose it by adding the keyword open as a modifier

With a base class framework, add member attributes and methods, and then add open modifiers to those members. Just like Java, Kotlin gives four open modifiers:

  • Public -> Open to all. Kotlin’s classes, functions and variables are public by default if they are not open
  • Internal -> Open only to this module internally, this is kotlin’s new keyword. For app development, this module refers to the app itself
  • Protected -> Only for yourself and subclasses
  • Private -> Open only to oneself, i.e. private

Note that these modifiers are used in front of classes and functions, and they all mean “open”. Quite simply, Open does not control access to an object, only whether it can reproduce, or, in plain English, whether the object is eligible to have children. Only classes with an open cap can be subclassed as base classes. And a function with an open hat means it can be overridden in a subclass. If they don’t wear an.open hat, they will be single and childless. If the function does not wear the open hat, the child of the class cannot modify it.

As for the four open modifiers, they are used to limit the number of external areas that are allowed to access an object, which is, in plain English, where a handsome man can make friends with a beautiful woman. Wearing “public” means that handsome men from all over the world can make friends with her. Wearing an intermal means that only handsome men from the country can make friends with her; Wearing a protected head means that only men from her work unit and those who work for her are allowed to make friends with her. Wearing a private head, means fat water does not flow out of the field, only the handsome boy in the work unit can make friends with this beautiful woman.

Open, private, private, private

5.3.2 Common Class Inheritance

/** * If you want a class to be a base class, you need to expose the class by adding the keyword open as the modifier */
open class Bird(var name: String.val sex: Int = MALE) {
    // All variables, methods, and classes are public by default, so public is omitted
// public var sexName:String
    var sexName: String

    init {
        sexName = getSexName(sex)
    }

    open protected fun getSexName(sex: Int): String {
        return if (sex == MALE) "Male" else "Mother"
    }

    fun getDes(tag: String) :String {
        return ${sexName} = ${sexName}
    }

    companion object BirdStatic {
        val MALE = 0
        val FEMALE = 1
        val UNKONW = -1
        fun judgeSex(sexName: String): Int {
            var sex: Int = when (sexName) {
                "Male"."Male" -> MALE
                "Mother"."Female" -> FEMALE
                else -> UNKONW
            }
            return sex
        }

    }
}
Copy the code

Declare a subclass

/** * &Note that the bird class already declares the property in the constructor, so the Duck class does not have to declare the property * & again
class Duck(name: String = "Duck".sex: Int = Bird.MALE) : Bird(name, sex) {

    override public fun getSexName(sex: Int): String {
        return if (sex == Bird.MALE) "It's a male duck." else "It's a female duck."}}Copy the code

Call:

     btn_simple_class8.setOnClickListener {
            var sexBird = if (count++ % 3= =0) Bird.MALE else Bird.FEMALE
            var duck = Duck(sex = sexBird)
            btn_simple_class8.text = duck.getDes("Bird Talk forest") + "-" + duck.getSexName(1)}Copy the code

Subclasses can also define new member attributes and member methods, or override superclass methods declared as open.

Override protecte fun getSexName(sex: Int): override protecte fun getSexName(sex: Int) Override fun getSexName(sex: Int): String {} * override fun getSexName(sex: Int): String {} * protected -- Override public fun getSexName(sex: Int): String {} */
class Ostrich(name: String = "The bird".sex: Int = Bird.MALE) : Bird(name, sex) {
    override public fun getSexName(sex: Int): String {
        return if (sex == MALE) "Male" else "Female"}}Copy the code

Outside calls

btn_simple_class9.setOnClickListener {
            var sexBird = if (count++ % 3= =0) Bird.MALE else Bird.FEMALE
            var ostrich = Ostrich(sex = sexBird)
            btn_simple_class9.text = ostrich.getDes("Bird Talk forest") + "-" + ostrich.getSexName(1)}Copy the code

5.3.3 abstract class

  • Abstract classes are decorated with the abstract keyword
  • Because abstract classes cannot be used directly, constructors do not have to assign values to default arguments
  • Abstract methods must be overridden in subclasses, so the keyword open can be omitted because the abstract method is of type open by default

Next, define an abstract class:

/** * &subclass constructor. Instead of adding var and val to the original input arguments, we must add var or val * &since abstract classes cannot be used directly, we do not need to assign */ to the default arguments
abstract class Chicken(name: String.sex: Int.var voice: String) : Bird(name.sex) {
    val numberArray: Array<String> = arrayOf("一"."二"."Three"."Four"."Five"."Six"."Seven"."Eight"."Nine"."Ten")

    Abstract methods must be overridden in subclasses, so the keyword open can be omitted because abstract methods are of type open by default
    abstract fun callOut(times:Int):String
}

Copy the code

Subclasses inherit from their parent class

class Cock(name: String = "Chicken".sex: Int = Bird.MALE, voice: String = "Cock-a-doodle") : Chicken(name, sex, voice) {
    override fun callOut(times: Int): String {
        var count = when {
            When the statement is greater than or less than, write the full criteria to each branch
            times <= 0 -> 0
            times >= 10 -> 9
            else -> times
        }
        return $sexName$name${voice} call ${numberArray[count]}}}Copy the code
class Hen(name: String = "Chicken".sex: Int = Bird.MALE, voice: String = "Cluck cluck.") : Chicken(name, sex, voice) {
    override fun callOut(times: Int): String {
        var count = when {
            When the statement is greater than or less than, write the full criteria to each branch
            times <= 0 -> 0
            times >= 10 -> 9
            else -> times
        }
        return $sexName$name${voice} call ${numberArray[count]}}}Copy the code

External calls:

 btn_simple_class10.setOnClickListener {

            btn_simple_class10.text = Cock().callOut(count++ % 10)

        }
 btn_simple_class11.setOnClickListener {

            btn_simple_class11.text = Hen().callOut(count++ % 10)}Copy the code

5.3.4 interface

  • Kotlin’s interface, like Java’s, is designed to implement multiple inheritance indirectly
  • An interface cannot define a constructor
  • The internal methods of an interface are usually overridden by the classes that implement them
  • Unlike Java, Kotlin allows a method to be implemented inside an interface, where all internal methods must be abstract

Define an interface as follows:

interface Behavior {

    // The methods inside the interface are abstract by default, so we can do without abstract, and we can also do without open
    open abstract fun fly(): String

    fun swim(): String

    // The Kotlin interface differs from Java in that the Kotlin interface internally allows implementation methods
    // If this method is not abstract, we cannot add abstract
    // However, this method is still of type open. All methods inside the interface are of type open by default

    fun run(): String {
        return "Most birds can't run properly. Only a few birds, such as ostriches and emus, can run well."
    }


    //Kotlin's interface allows you to declare abstract attributes that must be overridden by classes implementing the interface
    As with interinterface methods, open and abstract before abstract attributes can also be omitted
    //open abstract var skilledSports:String
    var skilledSports: String
}
Copy the code

Then other classes implement the Behavior interface by placing the interface name after the colon, just as class inheritance does. That is, the Java extends and Implement keywords are replaced by colons in Kotlin. Then override the abstract methods of that interface just as you override the abstract methods of an abstract class.

Let’s define a class override interface method

class Goose(name: String = "Goose".sex: Int = Bird.MALE) : Bird(name, sex), Behavior {
    override fun fly(): String {
        return "The goose can fly a little, but not high and not far."
    }

    override fun swim(): String {
        return "Goose, goose, goose, sing to the sky. White hair floating green water, anthurium waves."
    }

    // Since the interface already implements the run method, you don't need to implement it here, but you can implement it if you want
    override fun run(): String {
        return super.run()
    }

    // Overrides abstract attributes from the interface
    override var skilledSports: String = "Swimming"
}
Copy the code

External calls:

  btn_simple_class12.setOnClickListener {
            btn_simple_class12.text = when (count++ % 3) {
                0 -> Goose().fly()
                1 -> Goose().swim()
                else -> Goose().run()
            }
        }
Copy the code

5.3.5 Interface Proxy

It is true that the corresponding behaviors can be completed by implementing the interface, but there are a large number of birds. If every bird implements the Behavior interface, it can be imagined that the workload is huge.

Therefore, according to their habits, birds can be divided into: good at flying, good at swimming and good at running. Writing an interface for each Behavior is the same as implementing the Behavior interface. In order to make birds adapt to the behavior requirements of different scenarios, Kotlin introduced the interface proxy technology, that is, a class first declares the method inherited from an interface, but does not directly implement the interface, but passes the proxy class that has implemented the interface as a parameter to the previous class, which is equivalent to telling the previous class: The interface I have replaced you to achieve, you directly take to use it

Benefits: The input parameters can be used to transmit the corresponding proxy classes according to the specific business scenario, which means that how a bird flies, swims, and runs is not fixed but determined by the actual situation.

/** * The behavior of the birds */
class BehaviorFly : Behavior {
    override fun fly(): String {
        return "Soar in the sky."
    }

    override fun swim(): String {
        return "A phoenix in water is worse than a chicken."
    }

    override fun run(): String {
        return "Why go when you can fly?"
    }

    override var skilledSports: String = "Fly"
}
Copy the code
/** ** Waterfowl behavior */
class BehaviorSwim : Behavior {
    override fun fly(): String {
        return "It depends. The geese fly, but the penguins don't."
    }

    override fun swim(): String {
        return "Splashing in the water."
    }

    override fun run(): String {
        return "Drive a duck up a tree."
    }

    override var skilledSports: String = "Swimming"

}
Copy the code
/** * The behavior of the bird */
class BehaviorRun : Behavior {
    override fun fly(): String {
        return "It can't fly."
    }

    override fun swim(): String {
        return "Beyond the sea."
    }

    override fun run(): String {
        return super.run()
    }

    override var skilledSports: String = "Run"

}
Copy the code

Next, define a WildFowl class that references the proxy class, using the keyword BY to indicate that the interface will be implemented by the proxy class in the input parameter. The WildFowl class definition code looks like this:

/** * & Defines a wildfowl class that references a proxy class, with the keyword by indicating that the interface will be implemented by the proxy class in the input parameter */
class WildFowl(name:String.sex:Int=Bird.MALE,behavior:Behavior):Bird(name,sex),Behavior by behavior{
}
Copy the code

External calls:

 btn_simple_class13.setOnClickListener {
            var fowl = when (count++ % 6) {
                // Take the proxy class as an input parameter to create the instance
                0 -> WildFowl("The eagle", Bird.MALE, BehaviorFly())
                // Since the sex field is the default argument, you can assign behavior to the named argument
                1 -> WildFowl("Phoenix", behavior = BehaviorFly())
                2 -> WildFowl("Goose", Bird.FEMALE, BehaviorSwim())
                3 -> WildFowl("Penguin", behavior = BehaviorSwim())
                4 -> WildFowl("The ostrich", Bird.MALE, BehaviorRun())
                else -> WildFowl("Emu", behavior = BehaviorRun())
            }

            var action = when (count % 11) {
                in 0.3. -> fowl.fly()
                4.7.10 -> fowl.swim()
                else -> fowl.run()
            }
            btn_simple_class13.text = "${fowl.name}:$action"
        }
Copy the code

To summarize, Kotlin’s class inheritance differs from Java in the following aspects:

  • (1) Kotlin classes cannot be inherited by default. If you want to inherit, add open declaration; Java classes are allowed to be inherited by default, and a final declaration must be added to indicate that they cannot be inherited.
  • (2) Kotlin added the internal modifier in addition to the three open modifiers public, protected and private, indicating that it is only open to this module.
  • (3) The Java class inheritance keyword extends and the interface implementation keyword Implement are both replaced by colons in Kotin.
  • (4) Kotlin allows a method to be implemented inside an interface, whereas the internal methods of a Java interface can only be abstract methods.
  • (5) Kotlin introduced the concept of interface proxy (class proxy), whereas Java does not have proxy writing.

5.4 Several special classes

5.4.1 nested classes

A class can be defined in A separate code file or within another class, called A nested class, where class A is nested within class B.

Java’s nested classes allow access to members of an external class, whereas Kotlin’s nested classes do not

When a nested class is called, the class name of the external class is appended to the class name of the nested class

The next step is to define a nested class

class Tree(var treeName: String) {


    // Define a new class inside the class. This new class is called a nested class
    // Cannot access an external class member, such as treename

    class Flower(var flowerName: String) {
        fun getName(): String {
            return "This is a ${flowerName}"}}}Copy the code

When a nested class is called, the class name of the outer class is appended to the name of the nested class, which is equivalent to using the nested class as a static object of the outer class. The code for calling the nested Flower class looks like this:

 btn_simple_class14.setOnClickListener {
            val peachBlossom = Tree.Flower("Peach blossom")
            btn_simple_class14.text = peachBlossom.getName()
        }

Copy the code

5.4.2 inner class

Since Kotlin restricts nested classes from accessing members of external classes, what other way is there to do this? To solve this problem, Kotin added the keyword inner to denote inner, adding inner in front of the class of the nested class, so that the nested class is beautifully transformed into an inner class, which, like the nested class, has the advantage of being able to access the members of the external class. Thus, Kotlin’s inner classes are equivalent to Java’s nested classes, and Kotlin’s nested classes are restricted

class Tree(var treeName: String) {


    // Define a new class inside the class. This new class is called a nested class
    // Cannot access an external class member, such as treename

    class Flower(var flowerName: String) {
        fun getName(): String {
            return "This is a ${flowerName}"}}// A nested class with the prefix inner becomes an inner class
    inner class Fruit(var fruitName: String) {
        fun getName(): String {
            return ${treeName} $fruitName}}}Copy the code

Outside calls

Btn_simple_class15. SetOnClickListener {val peach Tree (" peach "). = Fruit (" peach ") btn_simple_class15. Text = peach. The getName ()}Copy the code

5.4.3 enumeration class

  • Kotlin changed Java’s enumeration type to an enumeration class
  • In addition to assigning values directly to variables inside an enumeration class, the corresponding information can also be obtained through several attributes of the enumeration value
  • The ordinal attribute is used to get the ordinal of the enumeration value, and the name attribute is used to get the name of the enumeration value
  • An enumeration variable is essentially an instance of the class, so if the enumeration class has a constructor, the enumeration variable must also call the corresponding constructor
enum class SeasonType(val seasonName: String) {
    SPRING("Spring"),
    SUMMER("Summer"),
    AUTUMN("Autumn"),
    WINTER("Winter")}Copy the code

External calls:

  btn_simple_class16.setOnClickListener {
            if (count % 2= =0) {
                btn_simple_class16.text = when (count++ % 4) {
                    SeasonType.SPRING.ordinal -> SeasonType.SPRING.name
                    SeasonType.SUMMER.ordinal -> SeasonType.SUMMER.name
                    SeasonType.AUTUMN.ordinal -> SeasonType.AUTUMN.name
                    SeasonType.WINTER.ordinal -> SeasonType.WINTER.name
                    else -> "Unknown"}}else {
                btn_simple_class16.text = when (count++ % 4) {
                    SeasonType.SPRING.ordinal -> SeasonType.SPRING.seasonName
                    SeasonType.SUMMER.ordinal -> SeasonType.SUMMER.seasonName
                    SeasonType.AUTUMN.ordinal -> SeasonType.AUTUMN.seasonName
                    SeasonType.WINTER.ordinal -> SeasonType.WINTER.seasonName
                    else -> "Unknown"}}}Copy the code

5.4.4 sealed class

Section 5.4.3 shows that when the external code evaluates enumeration values, the else branch is routinely added to the end of the WHEN statement. There are four enumeration variables inside the enumeration class SeasonType, so the when statement should have four branches; the last else branch is purely superfluous. The reason for this is that the WHEN statement doesn’t know that the SeasonType has four enumerations, so else branches are required just in case, unless the compiler decides that the existing branches are sufficient.

To solve the redundant branching problem of enumeration values (since there are only four types of SeasonType, there is no need for else judgment), Kotlin proposed the concept of “closed classes” a more restrictive enumerated class that has only and only its own instance objects inside, so it is a finite collection of its own instances or, Sealed class uses the method of nested class, its nested class is derived from itself, like a family tree, specify the eldest child, the second child, the third child, the last child to define the class of the sealed class with the keyword sealed as a mark

sealed class SeasonSealed {
    // Every nested class inside a sealed class must inherit from that class

    class Spring(var name: String) : SeasonSealed(a)class Sunmer(var name: String) : SeasonSealed(a)class Autumn(var name: String) : SeasonSealed(a)class Winter(var name: String) : SeasonSealed()}Copy the code

External calls:

    btn_simple_class17.setOnClickListener {
            var season = when (count++ % 4) {
                0 -> SeasonSealed.Spring("Spring")
                1 -> SeasonSealed.Sunmer("Summer")
                2 -> SeasonSealed.Autumn("Autumn")
                else -> SeasonSealed.Winter("Winter")}// A sealed class is a strictly enumerated class that is a finite collection
            // The sealed class ensures that the conditional branch covers all enumeration types, so else branches are no longer neededbtn_simple_class17.text = when (season) { is SeasonSealed.Spring -> season.name is SeasonSealed.Sunmer -> season.name is  SeasonSealed.Autumn -> season.name is SeasonSealed.Winter -> season.name } }Copy the code

5.4.5 Data Classes (javaBean Classes)

  • Defines a constructor that prefixes class with the keyword “data” and declares a full input parameter, and accomplishes the following
  • Automatically declare a property field with the same name as the constructor entry parameter
  • Automatically implement get/set methods for each property field
  • Automatically provides the equals method to compare the equality of consecutive data objects
  • The copy method is automatically provided to allow a complete copy of a data object or to individually modify the values of several fields after the copy
  • Allows you to provide a toString method that prints all field values saved in a data object
  • A data class must have a primary constructor and at least one input parameter, because its attribute fields correspond to the input parameters one by one. Without attribute fields, the data class cannot hold data and has no reason to exist
  • The main constructor must be preceded by the keyword val and var, which ensures that each input parameter is automatically declared with a property field of the same name
  • A data class has its own set of rules, so it must be a separate class, not another type of class, or the rules will conflict
data class Plant(var name:String.var stem:String.var leaf:String.var flower:String.var fruit:String.var seed:String){}Copy the code

External calls:

 var lotus = Plant("Lotus"."Lotus"."Lotus"."Lotus"."Lotus"."Lotus")

        // The copy method of a data class takes no arguments and copies exactly the same object

        var lotus2 = lotus.copy()
        btn_simple_class18.setOnClickListener {
            lotus2 = when (count++ % 2) {
                // The copy method takes parameters, indicating that the specified parameters are assigned additional values
                0 -> lotus.copy(flower = "Lotus")
                else -> lotus.copy(flower = "Lotus")}// The data class has its own equals method to determine whether two objects are the same

            var result = if (lotus2.equals(lotus)) "Equal" else "Range"

            btn_simple_class18.text =
                ${result}\n The first plant is described as ${lotus.tostring ()}\n The second plant is described as ${lotus2.tostring ()}\n"

        }

Copy the code

5.4.6 template class

  • The generic class
  • The definition format is similar to Java, with expressions such as

    following the class name
    ,b>
  • When the template class constructor is called externally, the class name is followed by “< parameter type >” to dynamically specify the actual parameter type
class River<T> (var name: String.var length: T) {
    fun getInfo(): String {
        var unit: String = when (length) {
            is String -> "米"
            is Number -> "m"
            else -> ""
        }
        return ${name} = $length$unit}}Copy the code

External calls:

btn_simple_class19.setOnClickListener {
            var river = when (count++ % 4) {
                // When a generic class declares an object, it follows the template class with "< parameter type >"
                0 -> River<Int>("Stream".100)
                // If the compiler knows the parameter type from the input parameter, it can also omit "< parameter type >".
                1 -> River("Waterfall".99.9f)
                1 -> River<Double>("Waterfall".55.5)
                else -> River("The river"."One thousand")
            }
            btn_simple_class19.text = river.getInfo()
        }
Copy the code