延迟初始化: by lazy 和 lateinit
by lazy
class PayFlyAnimal(val weight: Double, val age: Int, val color: String) {
val sex: String by lazy {
if (color == "yellow") "male" else "female"
}
}
fun main() {
val a = PayFlyAnimal(2.00, 2, "blue")
println(a.sex)
}
female
by lazy语法特点
1.该变量必须是引用不可变的(val),而不能通过var来声明。
2.在被首次调用时,才会进行赋值操作。一旦被赋值,后续它将不能被更改。
lazy的背后是接受一个lamdba并返回一个Lazy
另外系统会给lazy属性默认加上同步锁,也就是LazyThreadSafetyMode.SYNCHRONIZED,它在同一时刻只允许一个线程对lazy属性进行初始化,所以它是线程安全的。
如果认为该属性可以并行执行,没有线程安全问题,那么可以给lazy传递 LazyThreadSafetyMode.PUBLICATION参数。还可以给lazy传递LazyThreadSafetyMode.NONE参数,这将不会有任何线程方面的开销,当然也不会有任何线程安全的保证。
val sex2: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
//并行模式
if (color == "yellow") "male" else "female"
}
val sex3:String by lazy(LazyThreadSafetyMode.NONE) {
//不做任何线程保证也不会有任何线程开销
if (color == "yellow") "male" else "female"
}
lateinit主要用于var声明的变量,它不能用于基本数据类型,如Int,Long,所以需要使用 包装类替代。
class PayFlyAnimal2(val weight: Double, val age: Long, val color: String) {
lateinit var sex: String
var count by Delegates.notNull()
fun printSexAndCount() {
this.sex = if (color == "yellow") "male" else "female"
this.count = 666
println("sex:" + this.sex + ",count:" + this.count)
}
}
sex:female,count:666
Delegates.notNull
用var声明的基本数据类型变量也是可以延迟初始化的,可以通过Delegates.notNull
可以发现Kotlin不主张使用Java中的构造方法重载,来解决多个构造参数组合调用的问题。取而代之的是利用构造参数默认值以及使用val、var来声明构造函数的语法。
主从构造方法
Kotlin中的多构造方法之间建立了“主从”的关系。
1.通过constructor方法定义了一个新的构造方法,称为从构造方法。相应地,在类外部定义的构造方法称为主构造方法。每个类最多存在一个主构造方法和多个从构造方法,如果主构造方法存在注解或可见性修饰符, 也必须像从构造方法一样加上constructor关键字。
class PayKBird(age: Int) {
val age: Int
init {
this.age = age
}
constructor(newAge: Int, content: String) : this(newAge) {
println("content:$content")
}
}
val payKBird = PayKBird(12, "Bird")
println(payKBird.age)
content:Bird
12
class PayKBird constructor(age:Int) {}
internal class PayKBird2 @JvmOverloads constructor(age:Int) {}
每个从构造方法由两部分组成。一部分是对其他构造方法的委托,另一部分是由花括号包裹的代码块。执行顺序上会先执行委托的方法,然后执行自身代码块的逻辑。
通过this关键字来调用要委托的构造方法。如果一个类存在主构造方法,那么每一个从构造方法都要直接或间接地委托给它。
例子:
class PayKBird3(strDate: String) {
val payDate: String = strDate
constructor(timeStamp: Long) : this(Date(timeStamp))
constructor(date: Date) : this(SimpleDateFormat("yyyy-MM-dd").format(date))
}
fun main() {
val payKBird3 = PayKBird3(System.currentTimeMillis())
println(payKBird3.payDate)
}
2020-02-04
利用从构造方法就可以使用不同参数来初始化第三方类库中的类。最典型的例子是定制业务中特殊的View类。
class KView : View {
constructor(context: Context) : this(context, null)
constructor(context: Context, attributes: AttributeSet?) : this(context, attributes, 0)
constructor(context: Context, attributes: AttributeSet?, defStyleAttr: Int) : super(
context,
attributes,
defStyleAttr
) {
}
}
参考 kotlin核心编程