本章将详细讲解Kotlin中的一些基础知识,例如,第一行Kotlin代码应该如何写,Kotlin中常用的数据类型,包以及控制流。这些内容在所有的Kotlin程序中都会用到。
2.1 Kotlin的基本语法
在开始深入讲解Kotlin语言之前,让我们来先熟悉一下Kotlin的基本语法。Kotlin的语法很复杂,我们一开始也不需要了解太多,只需要满足本章的学习需要即可。对于一种语言来说,变量和函数(方法)是最重要的两类语法。由于Kotlin语法糖的存在,让本不支持函数语法的JVM支持将函数放到代码的最顶层,所以在本书中,就统一将Kotlin中的这类语法称为函数。本章的主要目的就是让读者学会定义变量和函数的基本方法。
2.1.1 定义变量
我们知道,绝大多数编程语言都有变量和常量的概念,例如,对于和Kotlin同源的Java类似,尽管没有常量语法,但可以使用final关键字定义一个不可修改的变量,其实就相当于常量。在Java中,不管是变量还是常量,数据类型和其他关键字都会放到变量名的前面,例如,下面的代码定义了2个Java变量和1个Java常量。
java代码
int n = 30; // Java变量
int ok; // 仅定义了ok变量,并未初始化,需要在后期初始化
final int m = 20; // Java常量,不允许再次设置m
ok = 123; // 后期初始化ok变量
m = 10; // 编译出错,因为m是常量(final变量)
其中m在初始化完成后,是不允许再次修改的。
在Kotlin中,定义变量有如下几个方面的Java不同。
➢ 位置不同:在Kotlin中,数据类型要放到变量后面,并且用冒号(:)分隔,这一点正好和Java相反
➢ 变量和常量需要关键字:在Kotlin中,定义变量需要用var开头,定义常量需要用val开头
➢ 数据类型首字母:在Kotlin中,数据类型都以大写字母开头,而在Java中,一般只有类、接口等复杂数据类型的名字才采用首字母大写的方式
➢ 如果在定义变量时未进行初始化,必须指定数据类型,如果在定义变量时进行了初始化,可以不指定数据类型,Kotlin编译器会自动根据等号右侧的值推导数据类型
下面是用Kotlin编写同样功能的代码。
kotlin代码
var n : Int = 30 // Kotlin变量,此处也可以不初始化,等待后期初始化
var ok: Int // 仅定义了ok变量,并未初始化,需要在后期初始化
val m: Int = 20 // Kotlin常量,不需要再次设置m
ok = 123 // 后期初始化ok变量
m = 10 // 编译出错,因为m是常量
var k = 100 // 自动推导变量k的数据类型
2.1.2 定义函数
不管是什么编程语言,函数的定义都分为如下几部分。
➢ 函数头,包括函数名和标识函数的关键字,如fun、function等
➢ 参数,包括参数名和参数类型
➢ 返回值,包括返回值类型,以及如果没有返回值时的类型是什么
现在让我们先回顾Java方法的定义。
java代码
// 返回值类型是int
int add(int m, int n)
{
return m + n;
}
// 没有返回值,返回类型是void
void process(int m)
{
System.out.println(m * m);
}
从这段Java代码可以看出,函数头只是写了一个函数名,并没有任何标识,参数定义只是正常的Java变量的定义,如果没有返回值时,返回void。
对于Kotlin函数来说,与Java方法的定义还是由很大差异的,下面先看一段同样功能的Kotlin函数的定义。
kotlin代码
fun add(m:Int, n:Int):Int
{
return m + n
}
fun process(m:Int): Unit
{
println(m * m)
}
我们可以看到,定义kotlin函数时,函数头除了包含函数名外,还必须包含fun关键字。至于参数,与定义kotlin变量的方式相同。如果kotlin函数有返回值,返回值类型在函数定义部分末尾指定,与函数定义部分用冒号(:)分隔。如果kotlin函数没有返回值,可以返回Unit,也可以什么都不返回(省略Unit),代码如下:
kotlin代码
fun process(m:Int)
{
println(m * m)
}
2.1.3 注释
对于一个复杂的程序,适当的注释是必要的。Kotlin中的注释与Java中的注释类似,也支持单行注释和块注释。
单行注释
// 这是一行注释
块注释
/* hello
world */
但kotlin注释更强大一些,kotlin块注释支持嵌套,代码如下:
kotlin代码
/*
hello
/* world */
*/
这几行注释放到Java代码中会有编译错误,因为Java不支持块注释嵌套。
2.2 基础数据类型
在Kotlin中,一切都是对象。任何变量都有相应的方法和属性。不过为了提高执行效率,Kotlin对部分数据类型进行的优化,变成了内置的数据类型。不过这些类型的变量使用起来就像普通的类,同样有自己的方法和属性。本节主要介绍了常用的数据类型,这些类型包括数值、字符、布尔类型和数组。
2.2.1 数值类型
Kotlin提供了如表2-1所示的内置数据类型。
表2-1 Kotlin提供的内置数据类型
下面的代码使用了这些内置类型定义了一些变量和常量。
kotlin代码
var m: Int = 20
var price: Double = 20.4
var flag: Boolean = true
val v1: Int = 100
val v2: Double = 20.4
Kotlin的数值和Java的数值一样,也有默认类型,例如,整数的默认类型是Int,浮点数的默认类型是Double。不过在Java中,如果将占用字节数少的变量赋给占用字节数多的变量,会自动进行转换,代码如下:
java代码
int m = 20;
byte n = 10;
m = n; // 将byte转换为int
long x = 20; // 将int转换为long
short value = 20;
m = value; // 将short转换为int
从这段Java代码可以看出, n是byte类型,value是short类型,n和value都赋给了m,m是int类型,所以byte和short隐式地转换为int类型。下面再看看实现同样功能的kotlin代码。
kotlin代码
var m = 20
val n: Byte = 10
m = n // 编译错误,无法将byte隐式转换为int
val x: Long = 20 // 可以将int类型的值隐式转换为long类型
val value: Short = 20
m = value // 编译错误,无法将short隐式转换为int
那如果非要将short类型转换为int类型怎么办呢?为了解决这个问题,Kotlin提供了一系列方法用来进行类型之间的转换。
➢ toByte(): 转换到Byte类型
➢ toShort(): 转换到Short类型
➢ toInt(): Int:转换到Int类型
➢ toLong(): Long:转换到Long类型
➢ toFloat(): Float:转换到Float类型
➢ toDouble(): Double:转换到Double类型
➢ toChar(): Char:转换到Char类型
前面给出的Java代码,如果用这些转换方法,对应的kotlin代码如下:
kotlin代码
var m = 20
val n: Byte = 10
m = n.toInt() // 通过toInt方法将Byte转换为Int
val x: Long = 20
val value: Short = 20
m = value.toInt() // 通过toInt方法将Short转换为Int
Kotlin与Java一样,也提供了一些特殊表示法,用于表示Long和Float 类型的值,以及十六进制和二进制(八进制目前还不支持)。
➢ 表示Long类型的值,在数值后面加L或l,如123L
➢ 表示Float类型的值,在数值后面加F或f,如123.1F
➢ 表示十六进制,在数值前面加0x,如0x1F
➢ 表示二进制,在数值前面加0b,如0b100101
如果数值较大,并不容易一下确定值的大小,因此Kotlin提供了下划线(_)作为数值分隔符,可以根据需要对数值进行分隔。分隔符可以任意插在数值之间,例如,12345678,可以写成123_456_78,也可以写成1_2_3_4_5_6_7_8,至于写成什么样,可以根据数值具体表示什么来决定。
kotlin代码
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