
1. 🌟 Kotlin:Java 的“超级进化体”?
Kotlin 是一门由 JetBrains 开发的 现代静态类型编程语言,支持 JVM、Android、JavaScript、Native 等多平台:

Kotlin 与 Java 深度兼容,Kotlin 会编译为 JVM 字节码,与 Java 共享运行环境(JVM);并且 Kotlin 与 Java 之间拥有 100% 互操作性,这意味着 Kotlin 可以和所有现有的 Java 源代码和库配合使用,即在同一项目中可混合调用 Java 和 Kotlin 代码。这样的特性允许公司逐步从 Java 迁移到 Kotlin,而无需重写整个项目。
2. 安装 Java 和 Kotlin 开发环境
你可以通过以下几种方式来开始 Kotlin 开发:
- 使用 IntelliJ IDEA 或 Android Studio: 这两款工具都原生支持 Kotlin,可以直接创建 Kotlin 项目。
- 使用在线 Kotlin 编译器: 如果你不想安装任何东西,可以访问 Kotlin 官方在线编译器,直接在浏览器中编写、运行 Kotlin 代码。
3. Kotlin 基础语法
输出 Hello World 示例:
fun main() {println("Hello, World!")
}
fun
是定义函数的关键字,main
是程序的入口函数。println
用来输出信息到控制台。
4. 变量和常量
在开始使用变量之前,我们必须先声明它。为了声明变量,Kotlin 提供了两个关键字 声明变量:
var
(for variable)val
(for value)
4.1. 变量
变量是程序中最常用的元素之一。变量是值的存储,可以是字符串、数字或其他内容。每个变量都有一个名称(或标识符)以区别于其他变量。可以通过变量的名称访问值。
Kotlin 中使用 var
关键字声明一个变量:
fun main() {var age: Int = 25println("初始年龄:$age")age = 26 // 修改变量值println("修改后的年龄:$age")
}
控制台输出结果:
4.2. 常量
变量是程序中最常用的元素之一。常量是不可变的变量,一旦初始化后不能再改变它的值。Kotlin 提供了 val
和 const
两种方式来声明常量。
4.2.1. 使用 val
声明常量
val
声明只读变量,即在运行时一旦赋值后不能再改变它的值。虽然 val
声明的变量不能重新赋值,但它在运行时是可以参与计算的。
fun main() {val pi: Double = 3.14159 // 声明一个常量 piprintln("圆周率的值是:$pi")
}
运行结果:
圆周率的值是:3.14159
如果我们试图修改只读变量的值时,IDEA 会提示 Val cannot be reassigned
错误:
🐖
val
只保证了变量引用的不可变性(对于引用类型),虽然禁止重新分配变量,但对引用类型的对象内部状态是允许修改的。
4.2.2. 使用 const
声明编译时常量
const
关键字声明编译时常量(带有 val),必须是在编译时就确定变量的值。通常用于声明那些在程序运行期间不会改变的值,并且在整个程序中是常量。它只能用于 Top-level
(顶层)变量或 object
中的属性,且必须是基本数据类型(例如 Int
, Double
, String
等)。
const val PI : Double = 3.14159 // 声明一个常量 pifun main() {println("圆周率的值是:$PI")
}
运行结果:
圆周率的值是:3.14159
当我们在局部函数或类的成员变量中使用 const
声明常量时,IDEA 会提示 Modifier 'const' is not applicable to 'local variable'
错误:
4.3. 命名规则
在声明变量时,我们需要遵循一些基本的命名规则和惯例:
4.3.1 基本命名规则
- 变量名必须由字母、数字和下划线组成,但必须以字母或下划线开头。
- Kotlin 是区分大小写的语言,变量
name
和Name
是不同的。 - 避免使用 Kotlin 关键字(例如
if
,while
,return
,val
,var
等),它们不能作为变量名。如果确实需要使用关键字,可以通过反引号(`
)包裹来实现。
4.3.2 命名惯例
- 变量:使用 小写字母 和 驼峰命名法(camelCase) 来命名变量
- 常量:使用 全大写字母 和 下划线 分隔单词(
UPPER_SNAKE_CASE
) - 类名和接口:使用 大驼峰命名法(PascalCase),即每个单词的首字母大写
- 函数:使用 小写字母 和 驼峰命名法(camelCase)
- 属性:使用 小写字母 和 驼峰命名法(camelCase)
5. 数据类型
5.1. 基本数据类型
Kotlin 是强类型语言,提供了多种基本数据类型,涵盖了数值、布尔、字符以及字符串:
- 数值类型:
Int
,Long
,Short
,Byte
,Double
,Float
- 布尔类型:
Boolean
- 字符类型:
Char
- 字符串类型:
String
5.1.1. 数值类型
-
Int: 整型,表示 32 位带符号整数,范围从
-2,147,483,648
到2,147,483,647
。val age: Int = 25
-
Long: 长整型,表示 64 位带符号整数,范围从
-9,223,372,036,854,775,808
到9,223,372,036,854,775,807
。val distance: Long = 1000000000L
-
Short: 短整型,表示 16 位带符号整数,范围从
-32,768
到32,767
。val height: Short = 180
-
Byte: 字节型,表示 8 位带符号整数,范围从
-128
到127
。val byteValue: Byte = 100
-
Float: 单精度浮点数,表示 32 位浮点数,适合存储小范围的小数。
val temperature: Float = 36.6f
-
Double: 双精度浮点数,表示 64 位浮点数,适合进行高精度计算。
val pi: Double = 3.14159
🐖 对于大数字数值,Kotlin 支持使用下划线(
_
)来提高可读性:fun main() {val oneMillion = 1_000_000 // 表示 1000000val largeNumber = 1_234_567_890 // 表示 1234567890val binaryNumber = 0b1010_1011_1100_1111 // 二进制表示val hexNumber = 0xAB_CD_EF // 十六进制表示 }
- 下划线 只能用作分隔符,不能出现在数字的开始或结束。
- 可以根据需要添加任意数量的下划线。
- 下划线不影响数字的实际值,它仅用于视觉上的分隔。
5.1.2. 布尔类型
-
Boolean: 布尔类型,表示
true
或false
,通常用于条件判断。val isAdult: Boolean = true
5.1.3. 字符类型
-
Char: 字符类型,表示一个 Unicode 字符。用单引号
'
包围。val grade: Char = 'A'
5.1.4 字符串类型
-
String: 字符串类型,表示一系列字符。可以用双引号
"
包围字符串。val name: String = "Kotlin"
5.2. 类型推断
类型推断(Type Inference)是 Kotlin 编译器的一个强大特性,允许编译器在没有显式指定类型的情况下推断出变量或表达式的类型。
这使得我们在声明时不需要显式声明类型 ,Kotlin 编译器会根据变量的初始值自动推断出变量的类型。
fun main() {val x:Int = 42val name:String = "Alice"val pi:Double = 3.14
}
在这个例子中,Kotlin 编译器会自动推断出 x
是 Int
类型;变量 name
类型被推断为 String
。
在 IDEA 中变量名后的类型显示为暗灰色,提示我们存在冗余:
5.3. 类型检测
类型检测(Type Checks)用于判断对象是否属于某个特定类型。
Kotlin 主要通过 is
操作符检查对象是否是指定类型的实例。它相当于 Java 中的 instanceof
。
基本语法:
if (obj is Type) {// obj 是 Type 类型的实例,可以安全使用
} else {// obj 不是 Type 类型的实例
}
5.4. 类型转换
5.4.1. 强制类型转换 (as
)
as
用于进行强制类型转换。如果对象不能转换为指定类型,Kotlin 会抛出 ClassCastException
转换异常。因此,使用 as
时需要确保对象的实际类型与目标类型一致。
fun forceConvert(obj: Any) {val str = obj as String // 如果 obj 不是 String 类型,这里会抛出 ClassCastExceptionprintln(str.length)
}
5.4.2. 安全类型转换 (as?
)
as?
是一个安全的转换操作符。如果转换成功,它会返回转换后的类型;如果转换失败,它会返回 null
,而不会抛出异常。
fun safeConvert(obj: Any) {val str = obj as? String // 如果 obj 不是 String 类型,str 会是 nullprintln(str?.length ?: "不是字符串") // 如果 str 为 null 输出 "不是字符串"
}
5.4.3. 智能类型转换
当使用 is
操作符进行类型检测时,Kotlin 会自动将该对象转换为检测的类型,我们可以直接访问该类型的属性和方法。
例如,当 obj is String
时,我们可以直接使用 obj
的 String
类型方法(如 .length
),而不需要显式地进行转换。
fun printStringLength(obj: Any) {if (obj is String) {// 在这里 obj 被智能转换为 String 类型,可以直接使用 String 类型的方法println("字符串的长度是: ${obj.length}")} else {println("不是一个字符串")}
}
6. 控制流程
Kotlin 的控制流程包括条件判断、循环控制、跳出和返回等基本结构。
6.1. 条件判断
6.1.1. if 表达式
if
表达式是一种控制流语句,用于根据条件执行不同的代码块,与 Java 类似,但 Kotlin 的 if
可以作为表达式使用,这意味着它能像函数调用或赋值操作那样返回一个值。
-
基本语法
if (condition) {// 如果条件为真,执行这里的代码 } else {// 如果条件为假,执行这里的代码 }
-
多个条件的
if-else
链val x = 10 if (x < 5) {// x < 5 } else if (x == 5) {// x == 5 } else {// x > 5 }
-
作为表达式使用,将
if
的结果赋值给变量val max = if (x > y) x else y println(max) // 输出最大值
6.1.2. when 表达式
when
语法类似于 Java 中的 switch
语句,但更为灵活。它可以用来匹配各种条件,如常量、范围、类型等。
-
基本语法
when (variable) {value1 -> {// 执行代码块}value2 -> {// 执行代码块}else -> {// 默认代码块} }
-
表达式作为条件
when
不仅仅能匹配常量,还能匹配表达式:val x = 10 when {x % 2 == 0 -> println("x is even")else -> println("x is odd") }
-
范围匹配
when
可以检查一个值是否在某个范围内:val x = 5 when (x) {in 1..10 -> println("x is between 1 and 10")!in 11..20 -> println("x is not between 11 and 20")else -> println("x is out of range") }
-
类型匹配
when
也可以根据对象的类型来进行判断:fun printType(obj: Any) {when (obj) {is String -> println("It's a String")is Int -> println("It's an Integer")else -> println("Unknown type")} }
-
多个条件匹配
可以在
when
中使用逗号分隔多个条件:val x = 3 when (x) {1, 3, 5 -> println("x is odd")2, 4, 6 -> println("x is even")else -> println("Unknown") }
6.2. 循环控制
6.2.1. for
循环
for
用于循环遍历任何提供了迭代器的对象(如 List
、Set
等) 。基本语法如下:
for (item: Int in ints) {// ......
}
遍历数组或集合
Kotlin 的 for
循环也可以用于遍历数组或集合。
val arr = arrayOf(1, 2, 3, 4, 5)
for (i in arr) {println(i)
}
数字区间遍历
-
遍历范围(闭区间)
在数字区间上范围遍历可以通过
..
运算符来创建一个闭区间(包含开始值和结束值):// 1 <= i <= 5 for (i in 1..5) {print(i) // 12345 }
-
遍历范围(半开区间)
使用
until
关键字可以创建一个半开区间,遍历时不包括结束值:// 1 <= i < 5 for (i in 1 until 5) {print(i) // 1234 }
-
步长遍历
通过
step
关键字指定步长来控制每次遍历的增量,实现跳步:// 10<= i <=1 for (i in 1..10 step 2) {print(i) // 13579 }
-
倒序遍历
使用
downTo
可以创建一个递减的范围:// 1 <= i <= 5 for (i in 5 downTo 1) {println(i) // 54321 }
6.2.2. while
循环
Kotlin 中的 while
、do-while
循环与 Java 类似,用于在条件为 true
时重复执行某个代码块:
while
循环在每次执行之前检查条件,如果条件为false
,则不会执行循环体。do-while
循环先执行一次循环体,然后再检查条件,因此保证至少执行一次。
while (condition) {// 循环体
}do {// 循环体
} while (condition)
6.3. 跳出和返回
与 Java 一样,Kotlin 中也使用 return
、break
和 continue
作为控制流程的关键字,它们用于在循环和函数中实现不同的跳转行为。
6.3.1. return
return
关键字用于从函数中返回,并可以指定返回值。如果在函数中调用 return
,函数会立即结束,控制流会返回到调用该函数的地方。如果是 Unit
类型(即没有返回值的函数),则 return
后不需要指定值。
fun add(a: Int, b: Int): Int {return a + b
}
return
不仅用于函数中,也可以用于跳出嵌套的循环(通常与标签一起使用)。
6.3.2. break
break
关键字用于立即跳出循环,不再执行后续的循环体代码。在嵌套循环中,break
会终止最内层的循环,程序将继续执行 break
后的代码。
fun main() {for (i in 1..5) {if (i == 3) {break // 当 i 等于 3 时,跳出循环}println(i)}println("循环结束")
}
在这个例子中,循环在 i == 3
时通过 break
跳出,因此数字 3 和 4 都不会被打印出来。控制台输出如下:
6.3.3. continue
continue
关键字用于跳过当前循环的剩余部分,直接进行下一次循环的条件判断。它不会终止循环,只会跳过当前迭代的剩余部分。
fun main() {for (i in 1..5) {if (i == 3) {continue // 跳过 i 为 3 的这次循环}println(i)}
}
在这个例子中,continue
跳过了 i == 3
时的打印操作,导致 3 没有被打印出来,其他数字依然按顺序输出:
6.3.4. 标签(label)
标签(label)是一种用于标识代码块(如循环或函数)的方式,允许指定跳出特定的代码块或循环。标签通常与 break
或 return
关键字一起使用,避免了在嵌套的循环或代码块中只依赖于内层结构的 break
或 return
,可以显式地指定跳出某个特定的循环或函数。
标签语法
标签的定义通常是通过在代码块前加上一个名称并使用 @
符号:
labelName@ 代码块
使用标签与 break
跳出嵌套循环
fun main() {outerLoop@ for (i in 1..5) {for (j in 1..5) {if (i == 3 && j == 3) {println("Found at i=$i, j=$j, jumping out of both loops")break@outerLoop // 跳出外层循环}println("i=$i, j=$j")}}println("Loop exited.")
}
在这个例子中,我们给外层循环加了一个标签 outerLoop@
。当我们在内层循环中遇到 i == 3
和 j == 3
的时候,通过 break@outerLoop
跳出的是外层循环,而不是内层循环。通常,break
只会跳出当前循环,但是通过使用标签,我们能控制跳出嵌套结构中的特定循环:
标签与 return
的结合使用
Kotlin 中函数可以使用函数字面量、局部函数与对象表达式实现嵌套。
return
默认的行为是从外层函数返回。标签限定之后的 return@标签
可以实现从 lambda
表达式中返回,不影响外层函数的返回。
fun foo() {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return // 非局部直接返回到 foo() 的调用者println(it)}println("this point is unreachable")
}
上述代码执行时,由于 return
的默认行为,在 (it == 3)
时会跳出循环直接从外层函数 foo()
返回,输出结果:
如果我们只想跳出循环,不想直接从外层函数 foo()
返回,就需要配合标签使用:
fun foo() {val list = listOf(1, 2, 3)list.forEach forEach@{if (it == 2) return@forEachprintln(it)}println("This will be printed")
}
使用标签的 return@forEach
会指定跳出循环,不会影响 foo()
函数的执行。"This will be printed"
会被打印出来。
🐖
return@标签
在非内联函数中使用是不允许的