本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
初始化的顺序
-
主构造函数里声明的属性
-
类级别的属性赋值
-
init初始化块里的属性赋值和函数调用
-
次构造函数里的属性赋值和函数调用
延迟初始化
-
lateinit关键字用来延迟初始化
-
isInitialized可以检查是否初始化完成
class classtest {var name = "Java"lateinit var code:Stringfun ready() {code = "hahah"}fun go() {if (::code.isInitialized) {println(code)}}
}
惰性初始化
只有在用到时才会初始化
val config by lazy { loadConfig() }
private fun loadConfig():String {println("loading...")return "ccc"
}
lateinit和by lazy
-
lateinit只修饰var,lazy修饰val
-
lateinit var只能用来修饰类属性,不能用来修饰局部变量,并且只能用来修饰对象,不能用来修饰基本类型(因为基本类型的属性在类加载后的准备阶段都会被初始化为默认值)。
-
lateinit var让编译期在检查时不要因为属性变量未被初始化而报错,也就是去掉了属性上的@NotNull修饰
-
by lazy后面的表达式只在第一次调用时执行一次,后续只返回结果
-
by lazy可以使用于类属性或者局部变量
-
by lazy初始化操作是线程安全的
初始化注意点
-
使用初始化块时,顺序非常重要,必须确保块中的所有属性已经完成初始化
-
初始化块中的函数里所用到得属性,也要确保已经初始化完成
-
类里面的属性按从上往下顺序初始化,在调用方法函数时,一定要确保属性已经初始化完成
继承
-
默认不可继承,如果要开放,需要open关键字
-
可以被覆写的方法也要open关键字修饰
-
用 is 来判断类型,用as来手动转换类型,并且kotlin可以进行智能类型转换
-
Any类是所有类的超类
open class Product(val name:String) {fun des() = "Product: $name"open fun load() = "Nothing..."
}class Normal : Product("normal"){override fun load() = "normal loading..."fun special() = "special"
}fun main() {val p:Product = Normal()println(p.load())println(p is Product)println(p is Normal)// if (p is Normal) {println((p as Normal).special())
// }//智能类型转换,不需要再asprintln(p.special())
}
嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使这2各类保持在一起是合理的
class Student {class Study {fun study(){println("study...")}}
}
fun main() {//嵌套类Student.Study().study()
}
数据类
-
data修饰符
-
实现了toString方法,equals方法和hashcode方法,==符号比较的是属性值
-
实现了copy函数,调用copy函数会生成一个新对象,构造方法走的是主构造方法,不会走次构造方法,也就是次构造函数里初始化的属性不会copy过来
-
支持解构语法
-
支持运算符重载
数据类使用条件
-
经常需要比较、复制或打印自身内容的类,数据类尤其适合
-
数据类必须有至少带一个参数的主构造函数
-
主构造函数的参数必须是val或是var
-
数据类不能使用abstract open sealed和inner修饰符
data class Coordinate(var x:Int, var y:Int){val isInBounds = x>0 && y>0//运算符重载operator fun plus(other:Coordinate) = Coordinate(x + other.x, y+other.y)
}fun main() {println(Coordinate(10,19))//解构语法val (x,y) = Coordinate(10,20)println("$x,$y")//运算符重载val c1 = Coordinate(10,20)val c2 = Coordinate(10,20)println(c1+c2)
}
单例类
- 使用object关键字可以定义单例类
object关键字有三种使用方式
-
对象声明,生成单例
-
对象表达式,就类似匿名内部类,new onClickListener
-
伴生对象,类似静态方法或是静态属性
枚举类
-
定义常量集合,也可以定义函数
-
when表达式不需要else
enum class Direction(private val coordinate: Coordinate){EAST(Coordinate(1,0)),WEST(Coordinate(-1,0)),SOURCE(Coordinate(-1,0)),NORTH(Coordinate(1,0));fun update(playCoordinate: Coordinate): Coordinate {return Coordinate(playCoordinate.x+coordinate.x, playCoordinate.y+coordinate.y)}
}fun main() {println(Direction.EAST)println(Direction.EAST.update(Coordinate(10,20)))
}
密封类
-
密封类可以用来定义一个类似枚举类的代数数据类型,但你可以更灵活地控制某个子类型
-
密封类可以有若干个子类,要继承密封类,这些子类必须和它定义在同一个文件里
sealed class LicenseStatus{//2个单例类object UnQualified:LicenseStatus()object Learining:LicenseStatus()//一个普通类,都是LicenseStatus的子类class Qualified(val licenseId:String) : LicenseStatus()
}class Driver(var status: LicenseStatus){fun checkLicense():String{return when(status){is LicenseStatus.UnQualified -> "没资格"is LicenseStatus.Learining -> "学习中"is LicenseStatus.Qualified -> "有资格,编号:${(this.status as LicenseStatus.Qualified).licenseId}"}}
}fun main() {val status = LicenseStatus.Qualified("1234")val driver = Driver(status)println(driver.checkLicense())
}
欢迎关注我的公众号查看更多精彩文章!