
field
针对你定义的每一个属性,Kotlin都会产生一个field,一个getter,以及一个setter,field用来存储属性数据,你不能直接定义field,Kottlin会封装field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方法决定你如何给属性赋值,所以只有可变属性才会有setter方法,尽管Kotlin会自动提供默认的getter和setter方法,但在需要控制如何读写属性数据时,你也可以自定义他们。
class Player {
var name: String = "jack"
get() = field.capitalize()
//重新赋值
set(value){field = value.trim()}
}
fun main() {
var p = Player()
p.name = "rose"
print(p.name)
}
计算属性
计算属性是通过一个覆盖的get或set运算符来定义,这是field就不需要了。
class Player {
val rolledValue
//通过一个覆盖的get或set运算符来定义
get() = (1..6).shuffled().first()
}
fun main() {
var p = Player()
print(p.rolledValue)
}
防范竞态条件
如果一个类属性即可空又可变,那么引用它之前必须保证它非空,一个办法是用also标准函数。
class AlsoTest {
var words:String?="hello"
fun saySomething(){
words?.also {
print("Hello ${it.toUpperCase()}")
}
}
}
fun main() {
val alsoTest = AlsoTest()
print(alsoTest.saySomething())
}
主构造函数
我们在Play类的定义头中定义一个主构造函数,使用临时变量为Player的各个属性提供初始值,在Kotlin中,为便于识别,临时变量(包括仅引用一次的参数),通常都会以下划线开头的名字命名。
//创建构造函数
class P(_name: String, _age: Int, _isNormal: Boolean) {
var name = _name
var age = _age
var isNormal = _isNormal
}
fun main() {
val p = P("Javk", 18, false)
//输出Javk
print(p.name)
}
在主构造函数里定义属性
Kotlin允许你不使用临时变量赋值,而是直接用一个定义同时指定参数和类属性,通常我们更喜欢用这个方式定义类属性,因为它会减少重复代码。
class P(_name: String, var _age: Int, var _isNormal: Boolean) {
var name = _name
}
fun main() {
val p = P("Javk", 18, false)
print(p.name)
}
次构造函数
有主就有次,对应主构造函数的次构造函数,我们可以定义多个次构造函数来配置不同的参数组合。
class P(var _name: String, var _age: Int, var _isNormal: Boolean) {
//次构造函数
constructor(name: String) : this(name, _age = 10, _isNormal = false)
}
fun main() {
val p = P("Rose")
//输出Rose
print(p._name)
}
使用次构造函数
使用次构造函数,定义初始化代码逻辑。
class P(var _name: String, var _age: Int, var _isNormal: Boolean) {
constructor(name: String) : this(name, _age = 10, _isNormal = false)
// 使用次构造函数,定义初始化代码逻辑。
constructor(name:String,age:Int) :this(name,age,_isNormal = false){
this._name =name.toUpperCase()
}
}
fun main() {
val p = P("Rose")
//输出Rose
print(p._name)
val p3 = P("aose",20)
// AOSE
print(p3._name)
}
默认参数
定义构造函数时,可以给构造函数参数指定默认值,如果用户调用时不提供值参,就使用这个默认值。
class T (var _name:String, var _age:Int = 20){
}
fun main() {
// val t =T("Jac")
val t = T(_name = "jack");
//输出20
print(t._age)
}
初始化块
初始化可以设置变量或值,以及执行有效性检查,如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。
class T (var _name:String, var _age:Int = 20){
//构建对象时,调用init函数
init {
require(_age>0){"age muse be positive"}
require(_name.isNotBlank()){"palyer must have a name."}
}
}
fun main() {
// val t =T("Jac")
val t = T(_name = "");
//输出20
print(t._age)
// 抛出异常
Exception in thread "main" java.lang.IllegalArgumentException: palyer must have a name.
at kotlin0.T.<init>(T.kt:8)
at kotlin0.T.<init>(T.kt:3)
at kotlin0.TKt.main(T.kt:14)
at kotlin0.TKt.main(T.kt)
Process finished with exit code 1
}
初始化顺序
➢主构造函数里声明的属性
➢ 类级别的属性赋值
➢ init初始化块里的属性赋值和函数调用
➢次构造函数里的属性赋值和函数调用
// 第一步执行 var age:Int
class Sudent(_name:String ,var age:Int) {
// 第二 类级别的属性赋值
var name = _name
var score = 10
private val hobby = "music"
val subject:String
//第三部init初始化块
init {
print("initializing" +
" student")
subject = "math"
}
//第四部 次构造函数里的属性赋值和函数调用
constructor(_name: String):this(_name,10){
score =20
}
}
fun main() {
Sudent("jack")
}
lateinit 延迟初始化
➢使用lateinit关键字相当于做了一个决定:在用它之前负责初始化
➢只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查
class Player4 {
//lateinit关键字相当于做了一个决定:在用它之前负责初始化
lateinit var equipment:String
fun ready(){
equipment = "Ak47"
}
fun battle(){
//只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查
if (::equipment.isInitialized)
print(equipment)
}
}
fun main() {
val p = Player4()
// p.ready()
p.battle()
}
by lazy 惰性初始化
➢延迟初始化并不是推后初始化的唯一方式,你也可以暂时不初始化某个变量,直到首次使用它,这个叫做惰性初始化。
class Player5(_name:String) {
var name = _name
//延迟初始化并不是推后初始化的唯一方式,你也可以暂时不初始化某个变量,
// 直到首次使用它,这个叫做惰性初始化。
val cofig by lazy { loadCongig()}
private fun loadCongig():String{
return "xxxx"
}
}
fun main() {
val player5 = Player5("jackal")
Thread.sleep(3000)
//三秒后输出xxxx
print(player5.cofig)
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)