Kotlin 基础语法

发布于:2025-03-21 ⋅ 阅读:(15) ⋅ 点赞:(0)
Kotlin 徽标

1. 🌟 Kotlin:Java 的“超级进化体”?

Kotlin 是一门由 JetBrains 开发的 现代静态类型编程语言,支持 JVM、Android、JavaScript、Native 等多平台:

适用于 JVM 的 Kotlin 编程语言Android 浏览器原生

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 = 25
    println("初始年龄:$age")
    age = 26 // 修改变量值
    println("修改后的年龄:$age")
}

控制台输出结果:

image-20250318102450036

4.2. 常量

变量是程序中最常用的元素之一。常量是不可变的变量,一旦初始化后不能再改变它的值。Kotlin 提供了 valconst 两种方式来声明常量。

4.2.1. 使用 val 声明常量

val 声明只读变量,即在运行时一旦赋值后不能再改变它的值。虽然 val 声明的变量不能重新赋值,但它在运行时是可以参与计算的。

fun main() {
    val pi: Double = 3.14159  // 声明一个常量 pi
    println("圆周率的值是:$pi")
}

运行结果:

圆周率的值是:3.14159

如果我们试图修改只读变量的值时,IDEA 会提示 Val cannot be reassigned 错误:

image-20250318104321740

🐖 val 只保证了变量引用的不可变性(对于引用类型),虽然禁止重新分配变量,但对引用类型的对象内部状态是允许修改的。

4.2.2. 使用 const 声明编译时常量

const 关键字声明编译时常量(带有 val),必须是在编译时就确定变量的值。通常用于声明那些在程序运行期间不会改变的值,并且在整个程序中是常量。它只能用于 Top-level(顶层)变量或 object 中的属性,且必须是基本数据类型(例如 Int, Double, String 等)。

const val PI : Double = 3.14159  // 声明一个常量 pi

fun main() {
    println("圆周率的值是:$PI")
}

运行结果:

圆周率的值是:3.14159

当我们在局部函数或类的成员变量中使用 const 声明常量时,IDEA 会提示 Modifier 'const' is not applicable to 'local variable' 错误:

image-20250318105701362

4.3. 命名规则

在声明变量时,我们需要遵循一些基本的命名规则和惯例:

4.3.1 基本命名规则
  • 变量名必须由字母、数字和下划线组成,但必须以字母或下划线开头
  • Kotlin 是区分大小写的语言,变量 nameName 是不同的。
  • 避免使用 Kotlin 关键字(例如 if, while, return, val, var 等),它们不能作为变量名。如果确实需要使用关键字,可以通过反引号(`)包裹来实现。
4.3.2 命名惯例
  • 变量:使用 小写字母驼峰命名法(camelCase) 来命名变量
  • 常量:使用 全大写字母下划线 分隔单词(UPPER_SNAKE_CASE
  • 类名和接口:使用 大驼峰命名法(PascalCase),即每个单词的首字母大写
  • 函数:使用 小写字母驼峰命名法(camelCase)
  • 属性:使用 小写字母驼峰命名法(camelCase)

5. 数据类型

5.1. 基本数据类型

Kotlin 是强类型语言,提供了多种基本数据类型,涵盖了数值、布尔、字符以及字符串:

  • 数值类型Int, Long, Short, ByteDoubleFloat
  • 布尔类型Boolean
  • 字符类型Char
  • 字符串类型String
5.1.1. 数值类型
  • Int: 整型,表示 32 位带符号整数,范围从 -2,147,483,6482,147,483,647

    val age: Int = 25
    
  • Long: 长整型,表示 64 位带符号整数,范围从 -9,223,372,036,854,775,8089,223,372,036,854,775,807

    val distance: Long = 1000000000L
    
  • Short: 短整型,表示 16 位带符号整数,范围从 -32,76832,767

    val height: Short = 180
    
  • Byte: 字节型,表示 8 位带符号整数,范围从 -128127

    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  // 表示 1000000
 val largeNumber = 1_234_567_890  // 表示 1234567890
 val binaryNumber = 0b1010_1011_1100_1111  // 二进制表示
 val hexNumber = 0xAB_CD_EF  // 十六进制表示
}
  • 下划线 只能用作分隔符,不能出现在数字的开始或结束。
  • 可以根据需要添加任意数量的下划线。
  • 下划线不影响数字的实际值,它仅用于视觉上的分隔。
5.1.2. 布尔类型
  • Boolean: 布尔类型,表示 truefalse,通常用于条件判断。

    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 = 42
    val name:String = "Alice"
    val pi:Double = 3.14
}

在这个例子中,Kotlin 编译器会自动推断出 xInt 类型;变量 name 类型被推断为 String

image-20250318144808884

在 IDEA 中变量名后的类型显示为暗灰色,提示我们存在冗余:

image-20250318144632776

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 类型,这里会抛出 ClassCastException
    println(str.length)
}
5.4.2. 安全类型转换 (as?)

as? 是一个安全的转换操作符。如果转换成功,它会返回转换后的类型;如果转换失败,它会返回 null,而不会抛出异常。

fun safeConvert(obj: Any) {
    val str = obj as? String  // 如果 obj 不是 String 类型,str 会是 null
    println(str?.length ?: "不是字符串")  // 如果 str 为 null 输出 "不是字符串"
}
5.4.3. 智能类型转换

当使用 is 操作符进行类型检测时,Kotlin 会自动将该对象转换为检测的类型,我们可以直接访问该类型的属性和方法。

例如,当 obj is String 时,我们可以直接使用 objString 类型方法(如 .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 可以作为表达式使用,这意味着它能像函数调用或赋值操作那样返回一个值。

  1. 基本语法

    if (condition) {
        // 如果条件为真,执行这里的代码
    } else {
        // 如果条件为假,执行这里的代码
    }
    
  2. 多个条件的 if-else

    val x = 10
    if (x < 5) {
        // x < 5
    } else if (x == 5) {
        // x == 5
    } else {
        // x > 5
    }
    
  3. 作为表达式使用,将 if 的结果赋值给变量

    val max = if (x > y) x else y
    println(max)  // 输出最大值
    
6.1.2. when 表达式

when 语法类似于 Java 中的 switch 语句,但更为灵活。它可以用来匹配各种条件,如常量、范围、类型等。

  1. 基本语法

    when (variable) {
        value1 -> {
            // 执行代码块
        }
        value2 -> {
            // 执行代码块
        }
        else -> {
            // 默认代码块
        }
    }
    
  2. 表达式作为条件

    when 不仅仅能匹配常量,还能匹配表达式:

    val x = 10
    when {
        x % 2 == 0 -> println("x is even")
        else -> println("x is odd")
    }
    
  3. 范围匹配

    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")
    }
    
  4. 类型匹配

    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")
        }
    }
    
  5. 多个条件匹配

    可以在 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 用于循环遍历任何提供了迭代器的对象(如 ListSet 等) 。基本语法如下:

for (item: Int in ints) {
    // ......
}
遍历数组或集合

Kotlin 的 for 循环也可以用于遍历数组或集合。

val arr = arrayOf(1, 2, 3, 4, 5)
for (i in arr) {
    println(i)
}
数字区间遍历
  1. 遍历范围(闭区间)

    在数字区间上范围遍历可以通过 .. 运算符来创建一个闭区间(包含开始值和结束值):

    // 1 <= i <= 5
    for (i in 1..5) {
        print(i) // 12345
    }
    
  2. 遍历范围(半开区间)

    使用 until 关键字可以创建一个半开区间,遍历时不包括结束值:

    // 1 <= i < 5
    for (i in 1 until 5) {
        print(i) // 1234
    }
    
  3. 步长遍历

    通过 step 关键字指定步长来控制每次遍历的增量,实现跳步:

    // 10<= i <=1
    for (i in 1..10 step 2) {
        print(i) // 13579
    }
    
  4. 倒序遍历

    使用 downTo 可以创建一个递减的范围:

    // 1 <= i <= 5
    for (i in 5 downTo 1) {
        println(i) // 54321
    }
    
6.2.2. while 循环

Kotlin 中的 whiledo-while 循环与 Java 类似,用于在条件为 true 时重复执行某个代码块:

  • while 循环在每次执行之前检查条件,如果条件为 false,则不会执行循环体。
  • do-while 循环先执行一次循环体,然后再检查条件,因此保证至少执行一次。
while (condition) {
    // 循环体
}

do {
    // 循环体
} while (condition)

6.3. 跳出和返回

与 Java 一样,Kotlin 中也使用 returnbreakcontinue 作为控制流程的关键字,它们用于在循环和函数中实现不同的跳转行为。

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 都不会被打印出来。控制台输出如下:

image-20250319094646094

6.3.3. continue

continue 关键字用于跳过当前循环的剩余部分,直接进行下一次循环的条件判断。它不会终止循环,只会跳过当前迭代的剩余部分。

fun main() {
    for (i in 1..5) {
        if (i == 3) {
            continue  // 跳过 i 为 3 的这次循环
        }
        println(i)
    }
}

在这个例子中,continue 跳过了 i == 3 时的打印操作,导致 3 没有被打印出来,其他数字依然按顺序输出:

image-20250319094757063

6.3.4. 标签(label)

标签label)是一种用于标识代码块(如循环或函数)的方式,允许指定跳出特定的代码块或循环。标签通常与 breakreturn 关键字一起使用,避免了在嵌套的循环或代码块中只依赖于内层结构的 breakreturn,可以显式地指定跳出某个特定的循环或函数。

标签语法

标签的定义通常是通过在代码块前加上一个名称并使用 @ 符号:

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 == 3j == 3 的时候,通过 break@outerLoop 跳出的是外层循环,而不是内层循环。通常,break 只会跳出当前循环,但是通过使用标签,我们能控制跳出嵌套结构中的特定循环:

image-20250319101519543

标签与 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() 返回,输出结果:

image-20250319110928426

如果我们只想跳出循环,不想直接从外层函数 foo() 返回,就需要配合标签使用:

fun foo() {
    val list = listOf(1, 2, 3)
    list.forEach forEach@{
        if (it == 2) return@forEach
        println(it)
    }
    println("This will be printed")
}

使用标签的 return@forEach 会指定跳出循环,不会影响 foo() 函数的执行。"This will be printed" 会被打印出来。

image-20250319111534143

🐖 return@标签 在非内联函数中使用是不允许的