作者:零摄氏度玫瑰_460 | 来源:互联网 | 2023-09-25 14:05
前言 在上一篇中主要讲解了Kotlin关于集合相关的知识点,在本篇中,将会对Kotlin的对象进行详解!
1. 对象 1.1 示例一(无构造函数) class Player { var name = "abc" get ( ) = field. capitalize ( ) set ( value) { field = value. trim ( ) } var age = 10 get ( ) = field. absoluteValueprivate set ( value) { field = value. absoluteValue} val rolledValueget ( ) = ( 1 until 6 ) . shuffled ( ) . first ( ) var words: String? = null fun saySomeThine ( ) { words? . also { "Hello ${ it. toUpperCase ( ) } " } . run ( :: println) } } fun main{ var player = Player ( ) player. name = "tom" player. words= "main hello" println ( player. name) println ( player. age) println ( player. rolledValue) player. saySomeThine ( ) }
定义了一个对象,里面有对应的成员属性。注意看这里面的分析点:
分析点1:分别实现了对应的get、set方法
,并且在对应的方法里实现了对应的逻辑。 分析点2:该成员变量并没有任何get、set方法
分析点3:在方法saySomeThine
里,对成员属性使用了.also
关键字,最后再打印 运行效果:
Tom10 4 main hello
从这个运行效果可以看到:对象里的成员,就算不实现对应的get、set方法,并且在没有使用private
情况下,在外部依旧可以调用对应的get、set方法
。
1.2 示例二(有主构造函数) class Player1 ( _name: String, _age: Int, _isNormal: Boolean) { var name = _nameget ( ) = field. toLowerCase ( ) private set ( value) { field = value. trim ( ) } private var age = _agevar isNormal = _isNormalfun playerInfo ( ) { println ( "name: $name ; age:$age ;isNormal $isNormal " ) } } fun main ( ) { var player = Player1 ( "Tom" , 20 , true ) player. playerInfo ( ) }
运行效果
name: tom; age:20 ; isNormal true
从这段代码看,这个Player1
应该是一个拥有有参构造方法的对象。而对应的_name、_age、_isNormal
,就是对应构造方法里的构造参数,有效期也仅在对应的构造方法里。
1.3 示例三(有主次构造函数) class Player2 ( _name: String, var age: Int = 12 , var isNormal: Boolean) { var name = _name get ( ) = field. capitalize ( ) private set ( value) { field = value. trim ( ) } fun playerInfo ( ) { println ( "name: $name ; age:$age ;isNormal $isNormal " ) } constructor ( name: String) : this ( name, age = 100 , isNormal = false ) { this . name = name. toUpperCase ( ) println ( "constructor----------" ) } init { 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 ( ) }
运行效果:
init---------- name: Tom; age:15 ; isNormal true init---------- name: Bob; age:12 ; isNormal false init---------- constructor---------- name: HQK; age:100 ; isNormal false
这次在代码里面加入了constructor
以及init
,constructor
的意思就是创建一个次构造函数;而init
相当于java里面的static代码块。里面对应的执行顺序在注释里标注清楚了。
而init
代码块里含有require
方法,这里面的意思就是:当里面的表达式不成立/false时,将直接报错,自定义错误信息就在后面闭包里实现。
1.4 示例四(延迟初始化) class Player3 { lateinit var equipment: Stringfun ready ( ) { equipment = "sharp knife" } fun battle ( ) { if ( :: equipment. isInitialized) println ( equipment) } } fun main{ var palyer3 = Player3 ( ) palyer3. ready ( ) palyer3. battle ( ) }
运行效果:
sharp knife
在之前的学习中,我们认知到,当我们定义变量的时候,要么一开始赋初始值,要么通过.?
表明这个变量为可空。但在对象的使用里,我既不想一开始赋初始值,也不想让这个变量为可空的,那就只有通过lateinit
表明这个属性变量需要在后面初始化(使用它之前)!
那万一在使用它之前未初始化该怎么办呢?岂不是就直接报空指针异常了?Kotlin也提供了对应的解决方案:只要无法确认 lateinit 变量是否完成初始化,可以执行 isInitialized 检查
1.5 示例五(惰性初始化) class Player4 ( _name: String) { var name = _nameval config by lazy { loadConfig ( ) } private fun loadConfig ( ) : Boolean { println ( "loading..." ) return false } } fun main{ var play4 = Player4 ( "Tom" ) ; println ( play4. config) }
运行效果
loading.. .false
这里我们看到,当定义成员属性时,使用了by lazy {}
的方式,让config
实现了惰性初始化。当使用play4.config
成员属性时,它才会初始化相应的操作。
1.6 示例六(初始化陷阱) class Player5 ( ) { init { blood = this . blood. times ( 4 ) } var blood = 100 }
当我们将变量放在init
闭包后时,将会发现代码居然报了语法错误。解决方案也很简单,只需要将init
闭包放在最后即可。
class Player6 ( ) { var blood = 100 init { blood = this . blood. times ( 4 ) } } fun main{ var play6= Player6 ( ) println ( play6. blood ) }
运行效果:
400
1.7 示例七(对象的继承) class Player7 ( ) { val name: Stringprivate fun firstLetter ( ) = name[ 0 ] init { name = "Jack" firstLetter ( ) } open class Product ( val name: String) { open fun description ( ) = "Product: $name " open fun load ( ) = "Nothing..." fun add ( num1: Int, num2: Int) = num1 + num2 } class LuxuryProduct : Product ( "Java" ) { override fun load ( ) = "Java " + description ( ) } } 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) println ( product is LuxuryProduct) println ( product is Player7. Product) sale ( product) sale ( product as Player7. Product) }
我们先看这几点分析点:
分析点1:和上面示例一样,当init代码块在对应的属性定义下方时,可在这闭包里初始化对应变量,即使变量是用val
修饰的,依然能够初始化。 分析点2:当我们想是用继承时,可以通过open class XXX
定义被继承的对象,里面的方法如果想要被子对象重写的话可使用open
修饰对应的方法。子类继承父类语法为:class 子类 : 父类
分析点3:当我们想进行对象的转换时,可使用as
关键字强转对应的对象。 运行效果
Jack Product: Java Java Product: Javatrue true Java Product: Java Java Product: Java
结束语 好了,本篇到这里就结束了,本想着在这篇吧对象讲完的,奈何发现内容太丰富了。还有很多很多,加上时间不允许了,还要写那个代码撸猫,所以暂时放到下一篇了。