前言
学习Kotlin中属性是经常用到的基础知识,Kotlin中属性的声明和使用 可空属性声明 可空类型的安全检测。if when 表达式,for while do..while循环,break continue控制循环终止和跳转。
属性
用关键字val和var来声明属性。val是只读,var是可变的。默认情况下,属性必须设置初始值:
val/var propertyName: propertyType= initValue
[getter]
[setter]
如果能从初始值或者[getter]方法返回值推断出类型,可以省略属性类型。初始值 [getter] 和[setter]方法都是可选的。
val a:String = "kotlin"
// 推断出属性的类型是String则省略
val b = "kotlin"
val c:String
get() = "kotlin"
// 推断出[getter]方法返回值是String则省略
val d
get() = "kotlin"
Kotlin中[getter]和[setter]允许自定义的。
// 单行表达式
val a = "info"
// 单行表达式
val b get() = "info"
// 有额外的逻辑,自定义[getter]
val c:String
get(){
...业务相关
return x
}
用val关键字声明只读属性,不允许自定义[setter]方法。
val a = "kotlin"
// 不允许自定义,会语法报错(编译不过代码报红)
set(value){}
var b = "kotlin"
// 允许自定义[setter]
set(value){}
var b = "kotlin"
set(value) {
field = "123"
}
fun test() {
println(b)// kotlin
b="1"
println(b)// 123
}
AndroidStudio中选择Tools->Kotlin->Show Kotlin ByteCode。点击Decompile按钮。
最终反编译得到
var a = "kotlin"
val b = "kotlin"// java中是final 修饰的
@NotNull
private String a = "kotlin";
@NotNull
private final String b = "kotlin";
field字段
在Property.kt的File文件中
var a:String = "kotlin"
set(value){
if(value.length > 0){
field = value
}else{
field = ""
}
}
field字段只能在我们自定义的[setter]方法的访问器中使用。理解为"幕后引用"
var a:String = "kotlin"
set(value){
a = value // 应该用field不能用a,否则死循环抛出StackOverFlowError异常。其实编译器左侧会有提示这里循环调用了
}
fun main(){
a = "java"
println(a)
}
抛出异常:
java.lang.StackOverflowError
幕后字段field的引入,在[setter]方法的访问器中直接给filed赋值,就不会再去调用属性的[setter]方法,规避了这个问题。
可空属性
当声明一个属性可为空,在属性的类型后加?
// 属性可为空
var a:String? = null
// 属性不为空
var b:String = "kotlin"
如果给一个不可为空的属性赋值null,kotlin编译器会报语法错误。
var a = "kotlin"
var b:String? = "java"
fun main(){
a = null // 报错
b = null // 正确
}
延迟初始化属性
kotlin中使用lateinit关键字完成一个属性的延迟初始化
private lateinit var a:String
fun test() {
a = "kotlin"
if (::a.isInitialized){
println(a)
}
}
在初始化前访问一个lateinit 修饰的属性会抛出lateinit property language has not bean initialized的异常。可以使用::propertyName.isInitialized方法判断属性是否已经初始化,::是一种绑定的语法。 用lateinit修饰的属性类型不可设置可空类型,否则编译器会报语法错误
private lateinit var a:String // 正确
private lateinit var a:String? // 错误
属性空类型检查
空指针异常(NullPointException),通常我们的判空:
if(property != null){
// ...业务
}
Kotlin中访问可空属性两种方式:一种断言双感叹号!!,一种是?. 断言通常是你确定不空。一般使用后者?.
var a:String? = "kotlin"
a!!.length // 不推荐使用
a?.length // 推荐使用
if语句
Kotlin中不仅是逻辑判断,还可以作表达式,这是一个很好的语法糖:
fun test() {
val a = 1
val b = 3
val max:Int = if (a>b){
println(a)
a
}else{
println(b)
b
}
println(max)
}
用if表达式取较大者,在Java中可以用三元运算符。if代码中只有一行表达式,我们可以省略花括号。通过Kotlin编译器推断出if表达式的返回值类型。
fun test() {
val a = 1
val b = 3
val max:Int = if (a>b){a}else{b}
// 简写,省略{}
val max1:Int = if (a>b) a else b
// 推断出结果是Int
val max2 = if (a>b) a else b
}
when语句
也可以是表达式
fun test() {
// 作为语句
when (a) {
"kotlin" -> { println("the kotlin") }
"java" -> { println("the java") }
"ios" -> { println("the ios") }
}
// 作为表达式,需要有else,除非编译器识别到所有情况,则可省略else块
val result = when (a) {
"kotlin" -> { println("the kotlin") }
"java" -> { println("the java") }
"ios" -> { println("the ios") }
else -> { println("the unknown") }
}
// 满足条件块中只有一行表达式,可省略{}
val result2 = when (a) {
"kotlin" -> println("the kotlin")
"java" -> println("the java")
"ios" -> println("the ios")
else -> println("the unknown")
}
}
可以使用(in)或者(!in)的区间作为条件分支,也可以使用is。(在kotlin中关键字in是一个操作符,a in b 相当于b.contains(a),is关键字去到了java中的instanceof关键字)
var number = 2
var type:Nothing?=null
fun test() {
// 使用区间作为条件判断
when(number){
in 0..10 ->{}
!in 10..20->{}
else ->{}
}
// 使用is作为条件判断
when(type){
is String ->{}
is Int ->{}
else ->{}
}
}
Kotlin1.3版本后,when后变量可以是一个表达式,可以从表达式中推断出变量的类型:
when (type = getType()) {
"kotlin" -> println("the kotlin language")
"java" -> println("the java language")
"ios" -> println("the ios language")
else -> println("the else logic")
}
for循环
提供了迭代器(iterator)的对象都可用for循环
for(item:Int in ints){...}
对一个区间进行for循环
//[0,10]闭区间
for(i:Int in 0..1){...}
// [0,10)开区间
for(i:Int in 0 until 10){...}
通过索引遍历一个数组或者一个list,用_Arrays.kt文件提供的扩展属性indices或者扩展方法withIndex()
// 扩展属性
public val <T> Array<out T>.indices: IntRange
get() = IntRange(0, lastIndex)
for(i in array.indices){...}
// 扩展方法
public fun <T> Array<out T>.withIndex(): Iterable<IndexedValue<T>> {
return IndexingIterable { iterator() }
}
for(i in array.withIndex()){...}
map常用的遍历方法:
// 遍历key
for(key in map.keys){...}
// 遍历value
for(value in map.values){...}
// 遍历key和value
for((key,value) in map){...}
(key,value)是结构声明。
while和do..while循环
// 先执行判断条件
while(a<b){...}
// 先执行循环体,再执行条件判断
do{...}while(a<b)
break和continue
控制循环跳转的关键字。break终止直接包含它的循环体,continue直接跳过本次循环,进入下次循环
fun main(){
for(i in 0..2){
if(i ==1){
break
}
println(i)
}
for(i in 0..2){
if(i == 1){
continue
}
println(i)
}
}
总结
主要是Kotlin中属性的声明和使用 可空属性声明 可空类型的安全检测。if when 表达式,for while do..while循环,break continue控制循环终止和跳转。