Kotlin学习笔记(三)基本语法

1.基础语法

1.1 包声明:

​ 代码文件的开头一般为包的声明,位于文件顶部:

1
2
3
package com.example.cuibin.kotlintest
import android.os.Bundle
import android.support.v7.app.AppCompatActivity

1.2 函数定义:

​ 函数定义使用关键字 fun,参数格式为:参数 : 类型

​ 在 Android Studio中输入fun关键字,编译器会帮开发者快速生成函数体,如下图:

001

​ 带有两个 Int 参数、返回 Int 的函数:

1
2
3
fun sum1(x: Int, y: Int): Int {
return x + y;
}

​ 将表达式作为函数体、返回值类型自动推断的函数:

1
2
fun sum2(x: Int, y: Int) = x + y
public fun sum3 (x: Int, y: Int): Int = x + y // public 方法则必须明确写出返回类型

​ 函数返回无意义的值:

1
2
3
fun sum3(x: Int, y: Int): Unit {
println("sum of $x and $y is ${x + y}")
}

Unit 返回类型可以省略:

1
2
3
fun sum4(x: Int, y: Int){
println("sum of $x and $y is ${x + y}")
}

​ 可变长参数函数

​ 函数的变长参数可以用 vararg 关键字进行标识:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 测试
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
vars(1,2,3,4,5)// 输出12345
}
}

​ lambda(匿名函数)

1
2
3
4
5
6
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
}

1.3 定义常量与变量:

​ 可变变量定义:var 关键字

1
2
3
4
var <标识符> : <类型> = <初始化值>
var x : Int = 1
var y = 2 // 系统自动推断变量类型为Int
y += 1

​ 不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)

1
2
3
4
5
val <标识符> : <类型> = <初始化值>
val a: Int = 1
val b = 1 // 系统自动推断变量类型为Int
val c: Int // 如果不在声明时初始化则必须提供变量类型
c = 1 // 明确赋值

​ 常量与变量都可以没有初始化值,但是在引用前必须初始化

​ 编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断

1.4 注释

​ 正如 Java 和 JavaScript,Kotlin 支持行注释及块注释。

1
2
3
4
// 这是一个行注释
/* 这是一个多行的
块注释。 */

1.5 字符串模版

​ $表示一个变量名或者变量值

​ $varName 表示变量值

​ ${varName.fun()} 表示变量的方法返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var x = 1
// 模板中的简单名称:
val s1 = "a is $a"
println(s1)
x = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"
println(s2)
}
}

1.6 NULL检查机制

​ 当某个变量的值可以为 null 的时候,必须在声明处的类型后添加 ? 来标识该引用可为空。

​ 如果 str 的内容不是数字返回 null

1
2
3
fun parseInt(str: String): Int? {
// ……
}

​ 使用返回可空值的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// 直接使用 `x * y` 可能会报错,因为他们可能为 null
if (x != null && y != null) {
// 在空检测后,x 和 y 会自动转换为非空值(non-nullable)
println(x * y)
}
else {
println("either '$arg1' or '$arg2' is not a number")
}
}

​ 或者

1
2
3
4
5
6
7
8
9
10
11
// ……
if (x == null) {
println("Wrong number format in arg1: '${arg1}'")
return
}
if (y == null) {
println("Wrong number format in arg2: '${arg2}'")
return
}
// 在空检测后,x 和 y 会自动转换为非空值
println(x * y)

1.7 类型检测及自动类型转换

is 运算符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换:

1
2
3
4
5
6
7
8
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` 在该条件分支内自动转换成 `String`
return obj.length
}
// 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
return null
}

​ 或者

1
2
3
4
5
fun getStringLength(obj: Any): Int? {
if (obj !is String) return null
// `obj` 在这一分支自动转换为 `String`
return obj.length
}

​ 甚至

1
2
3
4
5
6
7
fun getStringLength(obj: Any): Int? {
// `obj` 在 `&&` 右边自动转换成 `String` 类型
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}

2.基本数据类型

2.1 数字:

​ Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于Java的是,字符不属于数值类型,是一个独立的数据类型。Kotlin的数值类型和位宽度如下图所示:

类型 位宽度
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

​ 注意:Kotlin中字符不是数字

2.2 字面常量

下面是所有类型的字面常量:

  • 十进制:123
  • 长整型以大写的 L 结尾:123L
  • 16 进制以 0x 开头:0x0F
  • 2 进制以 0b 开头:0b00001011
  • 注意:8进制不支持

Kotlin 同时也支持传统符号表示的浮点数值:

  • Doubles 默认写法: 123.5, 123.5e10
  • Floats 使用 f 或者 F 后缀:123.5f

你可以使用下划线使数字常量更易读(自1.1起):

1
2
3
4
5
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010

2.3 数值表示

​ Kotlin 中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所有在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。

​ 在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val a: Int = 10000
println(a === a) // true,值相等,对象地址相等
//经过了装箱,创建了两个不同的对象
val boxedA: Int? = a
val anotherBoxedA: Int? = a
//虽然经过了装箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,对象地址不一样
println(boxedA == anotherBoxedA) // true,值相等
}
}

2.4 类型转换

​ 由于不同的表示方式,较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型。 这意味着在不进行显式转换的情况下我们不能把 Byte 型值赋给一个 Int 变量。

1
2
val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b // 错误

​ 我们可以代用其toInt()方法。

1
2
val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b.toInt() // OK

​ 每种数据类型都有下面的这些方法,可以转化为其它的类型:

1
2
3
4
5
6
7
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

​ 有些情况下也是可以使用自动类型转化的,前提是可以根据上下文环境推断出正确的数据类型而且数学操作符会做相应的重载。例如下面是正确的:

1
val l = 1L + 3 // Long + Int => Long

2.5 运算符

​ Kotlin支持数字运算的标准集,运算被定义为相应的类成员(但编译器会将函数调用优化为相应的指令)。

对于位运算,没有特殊字符来表示,而只可用中缀方式调用命名函数,例如:

1
val x = (1 shl 2) and 0x000FF000

这是完整的位运算列表(只用于 IntLong):

  • shl(bits) – 有符号左移 (Java 的 <<)
  • shr(bits) – 有符号右移 (Java 的 >>)
  • ushr(bits) – 无符号右移 (Java 的 >>>)
  • and(bits) – 位与
  • or(bits) – 位或
  • xor(bits) – 位异或
  • inv() – 位非