preface
In the previous article, we mainly explained Kotlin's knowledge points related to sets. In this article, we will explain Kotlin's objects in detail!
1. Object
1.1 example 1 (no constructor)
class Player { //Analysis point 1 var name = "abc" get() = field.capitalize() set(value) { field = value.trim() } var age = 10 get() = field.absoluteValue private set(value) { field = value.absoluteValue } val rolledValue //Take random number get() = (1 until 6).shuffled().first() var words: String? = null //Analysis point 2 fun saySomeThine() { //Analysis point 3 words?.also { "Hello ${it.toUpperCase()}" }.run(::println) } } fun main{ var player = Player() player.name = "tom" //player.age=-10 / / an error is reported here because set is changed to private player.words="main hello" println(player.name) println(player.age) println(player.rolledValue) player.saySomeThine() }
Defines an object with corresponding member properties. Pay attention to the analysis points:
- Analysis point 1: the corresponding get and set methods are implemented respectively, and the corresponding logic is implemented in the corresponding methods.
- Analysis point 2: this member variable does not have any get or set methods
- Analysis point 3: in the method saySomeThine, the. also keyword is used for the member attribute, and then printed
Operation effect:
Tom 10 4 main hello
From this operation effect, we can see that even if the members in the object do not implement the corresponding get and set methods, and do not use private, they can still call the corresponding get and set methods externally.
1.2 example 2 (with main constructor)
// ----------------Initialization class Player1( _name: String, _age: Int, _isNormal: Boolean) { var name = _name get() = field.toLowerCase() private set(value) { field = value.trim() } private var age = _age var isNormal = _isNormal fun playerInfo() { //println(_name) / / an error will be reported println("name: $name; age:$age ;isNormal $isNormal") } } fun main() { var player = Player1("Tom", 20, true) player.playerInfo() }
Operation effect
name: tom; age:20 ;isNormal true
From this code, Player1 should be an object with a parameter constructor. And the corresponding_ name,_ age,_ isNormal is the construction parameter in the corresponding construction method, and the validity period is only in the corresponding construction method.
1.3 example 3 (with primary and secondary constructors)
class Player2( _name: String, var age: Int = 12, //Execution sequence 1 var isNormal: Boolean) { var name = _name //Execution sequence 2 get() = field.capitalize() private set(value) { field = value.trim() } fun playerInfo() { println("name: $name; age:$age ;isNormal $isNormal") } //Secondary constructor [] this() here is equivalent to executing the primary constructor, equivalent to order 1 and 2 constructor(name: String) : this(name, age = 100, isNormal = false ) { this.name = name.toUpperCase() println("constructor----------") //Execution sequence 4 } init { // Execution sequence 3 //The initialization code block is executed when the class instance is constructed // You can check the value here, and throw an exception if the condition is met println("init----------") require(age > 10) { println("age must be positive") } require(name.isNotBlank()) { println("player must have a name") } } } fun main() { var player2=Player2("Tom", 20, true) player2.playerInfo() var player3 = Player2("bob", isNormal = false) player3.playerInfo() var player4=Player2("hqk") player4.playerInfo() }
Operation effect:
init---------- name: Tom; age:15 ;isNormal true init---------- name: Bob; age:12 ;isNormal false init---------- constructor---------- name: HQK; age:100 ;isNormal false
This time, constructor and init are added to the code. Constructor means to create a secondary constructor; Init is equivalent to static code block in java. The corresponding execution sequence is clearly marked in the notes.
The init code block contains the require method, which means that when the expression in it does not hold / false, an error will be reported directly, and the user-defined error information will be implemented in the following closure.
1.4 example 4 (delayed initialization)
class Player3 { lateinit var equipment: String fun ready() { equipment = "sharp knife" } fun battle() { if (::equipment.isInitialized) println(equipment) } } fun main{ var palyer3 = Player3() palyer3.ready() //This method must be called to use the corresponding property variable palyer3.battle() }
Operation effect:
sharp knife
In the previous study, we realized that when we define variables, we either assign initial values at the beginning or pass? Indicates that this variable is nullable. However, in the use of objects, I don't want to assign initial values at the beginning, nor do I want this variable to be nullable, so I can only use lateinit to indicate that this attribute variable needs to be initialized later (before using it)!
What if it is not initialized before using it? Isn't it just a null pointer exception? Kotlin also provides a corresponding solution: as long as you can't confirm whether the lateinit variable is initialized, you can perform the isInitialized check
1.5 example 5 (inert initialization)
class Player4(_name: String) { var name = _name val config by lazy { loadConfig() } private fun loadConfig(): Boolean { println("loading...") return false } } fun main{ var play4 = Player4("Tom"); println(play4.config) }
Operation effect
loading... false
Here we can see that when defining the member attribute, the method of by lazy {} is used to make config implement lazy initialization. When the play4.config member property is used, it initializes the corresponding operation.
1.6 example 6 (initialization trap)
class Player5() { init { //This will directly report an error blood = this.blood.times(4) } var blood = 100 }
When we put the variable after the init closure, we will find that the code actually reports a syntax error. The solution is also simple, just put the init closure at the end.
class Player6() { var blood = 100 init { //So you won't report an error blood = this.blood.times(4) } } fun main{ var play6=Player6() println(play6.blood ) }
Operation effect:
400
1.7 Example 7 (inheritance of objects)
class Player7() { val name: String private fun firstLetter() = name[0] init { name = "Jack" //Analysis point 1 firstLetter() } //--------------Inherit---------------- open class Product(val name: String) { //Analysis point 2 open fun description() = "Product: $name" open fun load() = "Nothing..." fun add(num1: Int, num2: Int) = num1 + num2 //This method cannot be overridden by subclasses } class LuxuryProduct : Product("Java") { //---Heavy load override fun load() = "Java " + description() } } /** * Type conversion */ fun sale(p: Player7.Product) { println(p.load()) } fun main() { val play7 = Player7() println(play7.name) val product = LuxuryProduct() product.description().run(::println) product.load().run(::println) //Type detection println(product is LuxuryProduct) println(product is Player7.Product) sale(product) sale(product as Player7.Product) //Analysis point 3 }
Let's look at these analysis points first:
- Analysis point 1: as in the above example, when the init code block is under the corresponding attribute definition, the corresponding variable can be initialized in this closure. Even if the variable is decorated with val, it can still be initialized.
- Analysis point 2: when we want to use inheritance, we can define the inherited object through open class XXX. If the methods inside want to be rewritten by sub objects, we can use open to modify the corresponding methods. The syntax of subclass inheriting parent class is: class subclass: parent class
- Analysis point 3: when we want to convert an object, we can use the as keyword to force the corresponding object.
Operation effect
Jack Product: Java Java Product: Java true true Java Product: Java Java Product: Java
Conclusion
Well, that's the end of this article. I wanted to finish talking about the object in this article. However, I found that the content was too rich. There are many, many, and time is not allowed. I have to write that code, so I'll put it in the next article for the time being.