1、在 Kotlin 中类可以有属性,我们可以使用 :
1.1、var 关键字声明可变属性:
var x = 5 // `Int` type is inferred
x += 1
1.2、val 关键字声明只读属性:
val a: Int = 1 // 立刻赋值
val b = 2 // `Int` 类型是自推导的
val c: Int // 没有初始化器时要指定类型
c = 3 // 推导型赋值
2、空安全
2.1、"?" -> 声明为可空的变量
var b: String? = "abc"
b = null
2.2、"?." -> 如果 b 不为空则返回长度,否则返回空。这个表达式的的类型是 Int?
b?.length()
2.3、"?:" -> 如果 "?:" 左边表达式不为空则返回,否则返回右边的表达式。(注意:右边的表带式只有在左边表达式为空是才会执行)
val l = b.length()?: -1
2.4、"!!" -> 返回一个非空的 b 值 或者如果 b 为空,就会抛出一个 NPE(空指针) 异常:
val l = b!!.length
2.5、"=="与"===" -> "=="判断值是否相等,"==="判断值及引用是否完全相等。
val num: Int = 128;
val a:Int? = num
val b:Int? = num
println(a == b)
print(a === b)
3、Kotlin常用操作符
3.1、"?:" Elvis操作符
如果 "?:" 左边表达式非空,elvis操作符就会返回左边的结果,否则返回右边的结果。请注意,仅在左侧为空的时候,右侧的表达式才会计算
val a = b?.length?:-1
//等同于:
val a: Int = if(b != null) b.length else -1
3.2、"as?" 安全转换
当使用 as 转型的时候,可能会经常出现 ClassCastException。 所以,现在可以使as?安全转型,当转型不成功的时候,它会返回 null。
注:在使用intent传值的时候,会出现空字符串不能用as强制转型,这是应该使用as?
val m: Int? = a as? Int
3.3、":" 冒号 用于类的继承,变量的定义
1、类型和超类型之间的冒号前要有一个空格
2、实例和类型之间的冒号前不要空格
//定义全局变量时
var str: String? = null
//类的继承与变量定义
class TestActivity<T : Serializable>(str: String) : Activity{}
3.4、"is" 类型判断符
检查某个实例是否是某个类型,如果判断出属于某个类型,那么判断后的分支中可以直接可当该类型使用,无需显示转换
fun getStringLength(obj: Any): Int? {
//obj在&&右边自动动转换成"String"类型
if (obj is String && obj.length > 0)
return obj.length
return null
}
3.5、".."、"until" 操作符 以及 "in" 和 "!in" 操作符
".." 代表从x到y,包括x和y,这是一个闭区间运算符,而
"until" 则是半闭区间运算符,代表从a到b范围内所有的值,包括a和不包括b。
"in" 代表在一个区间中,"!in" 代表不在一个区间中。
if (i in 1..10) { // 等价于 1 <= i && i <= 10
println(i)
}
//使用until函数,创建一个不包括其结束元素的区间
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
3.5.1、downTo()函数
//区间内循环:
for (i in 4 downTo 1){
print(i) //倒叙遍历
}
// print “4321”
3.5.2、step()函数 可以进行任意数量的迭代,而不是每次变化都是1
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
3.6、多行输入符 三个双引号
三引号的形式用来输入多行文本,也就是说在三引号之间输入的内容将被原样保留,之中的单号和双引号不用转义,其中的不可见字符比如/n和/t都会被保留
val str = """
one
two
"""
//等价于
val str = "one\ntwo"
val str = "one" +"\n"+"two"
3.7、"::"符号 得到类的Class对象
startActivity(Intent(this@KotlinActivity, MainActivity::class.java))
3.8、"@"符号
3.8.1、限定this的类型
class User {
inner class State{
fun getUser(): User{
//返回User
return this@User
}
fun getState(): State{
//返回State
return this@State
}
}
}
3.8.2、作为标签(见4.6详解)
3.9、"$"操作符
字符串可以包含模板表达式,及一小段代码,会求值并把结果包含到字符串中。模板字符串以美元符号$开头,由一个简单的名字构成:
val value:Int=5;
val str:String="the value is $value"
println("itemB:$itemB")
//字符串模板
var userInfo = "name:${user.name}, age:$age"
或花括号括起来的任意表达式
val g:Int=2
val h:Int=3
val str:String="g+h=${g+h}"
转义字符串和原生字符串都支持模板字符串。如果想要在原生字符串中使用$(它不支持反斜杠转义),可以使用以下语法:
val str:String="""the price is ${'$'}199"""
4、条件表达式的使用
4.1、"if/else" 语句规则:
①if后的括号不能省略,括号里表达式的值最终必须返回的是布尔值
②如果条件体内只有一条语句需要执行,那么if后面的大括号可以省略,但这是一种极为不好的编程习惯。
③对于给定的if,else语句是可选的,else if 语句也是可选的
④else和else if同时出现时,else必须出现在else if 之后
⑤如果有多条else if语句同时出现,那么如果有一条else if语句的表达式测试成功,那么会忽略掉其他所有else if和else分支。
⑥如果出现多个if,只有一个else的情形,else子句归属于最内层的if语句
4.1.1、传统用法
val a = 10
val b = 20
var max_0: Int = a
if (a > b) {
max_0 = a
} else {
max_0 = b
}
println("----------------------------------")
println("max_0:$max_0")
println("----------------------------------")
// Log
--------------
max_0:20
--------------
4.1.2、作为表达式
var max_1 = if (a > b) a else b
println("--------------")
println("max_1:$max_1")
println("--------------")
//Log
--------------
max_1:20
--------------
4.1.3、作为代码块
println("--------------")
val max_2 = if (a > b) {
println("Choose a")
a
} else {
println("Choose b")
b
}
println("max_2:$max_2")
println("--------------")
// Log
--------------
Choose b
max_2:20
--------------
if 作为代码块时,最后一行必须为该块的返回值.
如果 if 表达式只有一个分支, 或者分支的结果是 Unit , 它的值就是 Unit 。
4.2、"when"
when会对所有的分支进行检查直到有一个条件满足。 when 可以用做表达式或声明。
如果用作表达式的话,那么满足条件的分支就是总表达式。
如果用做声明,不满足条件的分支的的的值会被忽略,只保留满足条件的分支,而且返回的值也是最后一个表达式的值。
4.2.1、传统用法
val x : Int = 10
when (x) {
9 -> println("x:${x + 10}")
10 -> println("x:$x")
else -> print("x:$x")
}
4.2.2、分支条件一致
如果有分支可以用同样的方式处理的话, 分支条件可以连在一起处理。
when (x) {
0,1 -> print("x == 0 or x == 1")//同样的方式处理
else -> print("otherwise")
}
4.2.3、使用任意表达式作为分支的条件
when (x) {
parseInt(s) -> print("s encode x")
else -> print("s does not encode x")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
4.2.4、作为表达式
val hasPrefix = when (x) {
is String -> x.startsWith("prefix")
else -> false
}
4.3、"for"
for 循环通过任何提供的迭代器进行迭代。 语法如下:
for (item in collection)
print(item)
//如果遍历list或者array可以通过索引进行迭代:
for (i in array.indices)
print(array[i])
4.4、"while" 循环
4.4.1、"while"语句:while语句在循环刚开始时,会计算一次布尔表达式的值,如果满足条件,进入循环,
如果不满足条件,将跳出循环。而在while语句的下一次迭代开始前会计算再一次布尔值,如此重复。
while (x > 0) {
x--
}
4.4.2、"dowhile"语句:dowhile语句与while语句类似,唯一的区别是doWhile语句会至少执行一次,即便布尔表达式的第一次计算就是false。而while语句中,如果 布尔表达式的第一次计算的值是false,该循环不会执行。
4.5、返回与跳转 Kotlin中有"return"、"break"、"continue"等三种返回跳转操作符。
4.5.1、"return" ①指定一个方法返回什么值 ②导致当前方法结束,并返回返回指定的值
fun main(args: Array<String>) {
println("testA:${testA(10)}")
println("----------")
println("testB:${testB(10)}")
}
fun testA(a : Int):Int{
if (a > 0) {
return -1
} else {
return 1
}
}
fun testB(a : Int):Int{
println("a:$a")
if (a > 0) {
return -1
} else {
return 1
}
a++
print("a:$a")
}
// Log打印
testA:-1
----------
a:10
testB:-1
4.5.2、"break" 结束最近的闭合循环,不执行循环中剩余的语句
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
for (itemA in arraysA) {
for (itemB in arraysB) {
if (itemB > 2) {
break
}
println("itemB:$itemB")
}
if (itemA == "C") {
break
}
println("itemA:$itemA")
}
// Log
itemB:1
itemB:2
itemA:A
itemB:1
itemB:2
itemA:B
itemB:1
itemB:2
从Log打印可以看出,第一个break结束的是for (itemB in arraysB)这个循环,
而第二个break结束的是for (itemA in arraysA),它们的共通点就是结束都是距离它们最近的一个循环。
4.5.3、"continue" 跳到最近的闭合循环的下一次循环
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
continue
}
println("itemB:$itemB")
}
if (itemA == "C") {
continue
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log
itemB:1
itemB:2
i:4
itemA:A
---------
itemB:1
itemB:2
i:4
itemA:B
---------
itemB:1
itemB:2
itemB:1
itemB:2
i:4
itemA:D
---------
从上述Log上,可以清楚看到,两个循环分别循环了四次,但是在碰到continue时,会跳出当前循环并执行下一次循环。
4.6、标签 在 Kotlin 中表达式可以添加标签,标签通过@结尾来表示,比如:abc@,fooBar@
loop@ for (i in 1..100){
//...
}
4.6.1、"break"和标签
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
loop@ for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
break@loop
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log打印
itemB:1
itemB:2
从Log打印,第一个循环执行了一次,第二个循环执行了两次,便跳出了封闭的循环。
意味着break跳到标签后边的表达式,并不再执行此表达式直接跳过,执行后边的语句。
4.6.2、"continue"和标签
val arraysA = listOf("A", "B", "C", "D")
val arraysB = listOf(1,2,3,4)
loop@ for (itemA in arraysA) {
var i : Int = 0
for (itemB in arraysB) {
i++
if (itemB > 2) {
continue@loop
}
println("itemB:$itemB")
}
println("i:$i")
println("itemA:$itemA")
println("---------")
}
// Log打印
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
之前说过,continue是跳到最近的闭合循环的下一次循环,但是加上标签以后,直接跳转到了第一个循环,也就是for (itemA in arraysA),
并没有执行最近的闭合循环的下一次循环。意味着continue直接跳转到标签后面的语句并执行。
4.6.3、"return"和标签
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
foo()
}
fun foo() {
ints.forEach {
if (it ==0) return@forEach
println(it)
}
}
// Log打印
1
2
3
从Log打印可以看出,return会跳转到标签后边的表达式处,并执行该表达式。
4.6.4、命名函数自动定义标签
foo outer() {
foo inner() {
return@outer
}
}
4.6.5、作用域
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
list@
foo()
}
fun foo() {
ints.forEach {
if (it ==0) return@forEach
println(it)
}
//return @list//这么调用会报错,会提示“Unresolved reference:@list”
}
从作用域来看,标签和变量是一致的,都有相对应的作用域。在main方法里面定义了一个标签list@,在foo方法里面调用时,
提示“Unresolved reference:@list”,意味着list标签的作用域应该在main方法里,在foo方法里并不能够调用。
感谢
https://github.com/huanglizhuo/kotlin-in-chinese
http://blog.csdn.net/IO_Field/article/details/52842596
http://blog.csdn.net/jhj_24/article/details/53887820