MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kotlin基础语法与类型系统详解

2021-02-087.4k 阅读

Kotlin基础语法

变量声明

在Kotlin中,变量声明使用 var 关键字用于可变变量,val 关键字用于不可变变量(类似于Java中的 final 变量)。例如:

// 声明一个可变变量
var name: String = "John"
// 声明一个不可变变量
val age: Int = 30

这里,: String: Int 是类型声明。Kotlin 也支持类型推导,所以在很多情况下可以省略类型声明:

var name = "John"
val age = 30

Kotlin编译器会根据初始化值自动推断变量的类型。

数据类型

Kotlin的数据类型分为基本类型和引用类型。基本类型包括数值类型(ByteShortIntLongFloatDouble)、字符类型(Char)、布尔类型(Boolean)和字符串类型(String)。

  1. 数值类型

    • Byte:8位有符号整数,范围是 -128 到 127。
    • Short:16位有符号整数,范围是 -32768 到 32767。
    • Int:32位有符号整数,范围是 -2147483648 到 2147483647。
    • Long:64位有符号整数,范围是 -9223372036854775808 到 9223372036854775807。
    • Float:32位单精度浮点数。
    • Double:64位双精度浮点数。

    示例:

    val byteValue: Byte = 10
    val shortValue: Short = 1000
    val intValue: Int = 100000
    val longValue: Long = 1000000000000000000L
    val floatValue: Float = 3.14f
    val doubleValue: Double = 3.141592653589793
    

    注意,Long 类型的字面值需要在数字后面加上 LFloat 类型的字面值需要在数字后面加上 f

  2. 字符类型 Char 类型表示单个字符。字符需要用单引号括起来。例如:

val charValue: Char = 'A'
  1. 布尔类型 Boolean 类型只有两个值:truefalse。例如:
val isDone: Boolean = true
  1. 字符串类型 String 类型用于表示文本。字符串可以用双引号括起来。Kotlin 字符串支持模板表达式,通过 ${} 语法将变量或表达式嵌入到字符串中。例如:
val name = "John"
val message = "Hello, $name!"
val result = 10 + 20
val expressionMessage = "The result is ${10 + 20}."

运算符

Kotlin 提供了丰富的运算符,包括算术运算符、比较运算符、逻辑运算符、位运算符等。

  1. 算术运算符

    • +:加法
    • -:减法
    • *:乘法
    • /:除法
    • %:取模

    示例:

    val a = 10
    val b = 3
    val sum = a + b
    val difference = a - b
    val product = a * b
    val quotient = a / b
    val remainder = a % b
    
  2. 比较运算符

    • ==:等于
    • !=:不等于
    • >:大于
    • <:小于
    • >=:大于等于
    • <=:小于等于

    示例:

    val num1 = 10
    val num2 = 20
    val isEqual = num1 == num2
    val isGreater = num1 > num2
    
  3. 逻辑运算符

    • &&:逻辑与
    • ||:逻辑或
    • !:逻辑非

    示例:

    val condition1 = true
    val condition2 = false
    val andResult = condition1 && condition2
    val orResult = condition1 || condition2
    val notResult =!condition1
    
  4. 位运算符

    • and:按位与
    • or:按位或
    • xor:按位异或
    • inv:按位取反
    • shl:左移
    • shr:右移
    • ushr:无符号右移

    示例:

    val num = 5 // 二进制表示为 00000101
    val andResult = num and 3 // 3 的二进制表示为 00000011,结果为 00000001(即 1)
    

控制流语句

  1. if - else 语句 if - else 语句用于条件判断。在 Kotlin 中,if 表达式是有返回值的,这意味着它可以用作一个值。
val num = 10
val result = if (num > 5) {
    "Greater than 5"
} else {
    "Less than or equal to 5"
}
  1. when 语句 when 语句类似于 Java 中的 switch - case 语句,但功能更强大。它可以匹配多种类型,包括对象、范围等。
val day = 3
val dayName = when (day) {
    1 -> "Monday"
    2 -> "Tuesday"
    3 -> "Wednesday"
    4 -> "Thursday"
    5 -> "Friday"
    6 -> "Saturday"
    7 -> "Sunday"
    else -> "Invalid day"
}

when 也可以用于更复杂的匹配,比如范围匹配:

val num = 15
val result = when (num) {
    in 1..10 -> "In the range 1 to 10"
    in 11..20 -> "In the range 11 to 20"
    else -> "Outside the range"
}
  1. for 循环 for 循环用于遍历集合或区间。
// 遍历数组
val numbers = arrayOf(1, 2, 3, 4, 5)
for (number in numbers) {
    println(number)
}

// 遍历区间
for (i in 1..5) {
    println(i)
}

// 反向遍历区间
for (i in 5 downTo 1) {
    println(i)
}

// 遍历区间并指定步长
for (i in 1..5 step 2) {
    println(i)
}
  1. whiledo - while 循环 while 循环在条件为真时执行循环体。do - while 循环先执行一次循环体,然后再检查条件。
var num = 0
while (num < 5) {
    println(num)
    num++
}

var num2 = 0
do {
    println(num2)
    num2++
} while (num2 < 5)

Kotlin类型系统

类型层次结构

Kotlin 的类型层次结构以 Any 为所有非空类型的根类型。Any 类定义了 equals()hashCode()toString() 方法。所有类型,包括基本类型的包装类,都继承自 Any

Nothing 类型是所有类型的子类型,它表示一个永远不会有值的类型。例如,一个总是抛出异常的函数的返回类型就是 Nothing

fun throwException(): Nothing {
    throw RuntimeException("This function always throws an exception")
}

Unit 类型只有一个值,即 Unit。它类似于 Java 中的 void,用于表示没有有意义返回值的函数。例如:

fun printMessage(): Unit {
    println("This is a message")
}

在 Kotlin 中,Unit 类型的返回值可以省略不写,所以上面的函数可以写成:

fun printMessage() {
    println("This is a message")
}

可空类型

在 Kotlin 中,类型默认是非空的。如果一个变量可能为 null,需要在类型后面加上 ? 来表示可空类型。

var name: String? = null

访问可空类型变量的属性或调用其方法时,需要进行空值检查。有几种方式可以做到这一点:

  1. 使用 if 语句进行显式检查
var name: String? = null
if (name!= null) {
    println(name.length)
}
  1. 安全调用操作符 ?. 安全调用操作符允许在对象不为 null 时调用其方法或访问其属性,否则返回 null
var name: String? = null
val length = name?.length
  1. Elvis 操作符 ?: Elvis 操作符用于在对象为 null 时提供一个默认值。
var name: String? = null
val result = name?: "Default name"
  1. 非空断言操作符 !! 非空断言操作符将可空类型转换为非空类型,如果对象为 null,会抛出 NullPointerException。使用时需谨慎。
var name: String? = null
val length = name!!.length // 如果 name 为 null,这里会抛出 NullPointerException

类型转换

  1. 自动类型转换 Kotlin 支持数值类型的自动转换。例如,Byte 类型可以自动转换为 ShortIntLongFloatDouble
val byteValue: Byte = 10
val intValue: Int = byteValue
  1. 显式类型转换 对于不能自动转换的类型,需要进行显式类型转换。例如,将 Int 转换为 Byte
val intValue: Int = 100
val byteValue: Byte = intValue.toByte()

Kotlin 为每个数值类型提供了转换方法,如 toByte()toShort()toInt()toLong()toFloat()toDouble()

泛型

泛型允许在定义类、接口和函数时使用类型参数。例如,定义一个简单的泛型类:

class Box<T>(val value: T) {
    fun getValue(): T {
        return value
    }
}

使用泛型类:

val intBox = Box(10)
val stringBox = Box("Hello")

泛型函数:

fun <T> printValue(value: T) {
    println(value)
}

调用泛型函数:

printValue(10)
printValue("Hello")

泛型还支持类型限定,例如:

fun <T : Number> printDoubleValue(value: T) {
    println(value.toDouble())
}

这里,类型参数 T 必须是 Number 或其子类型。

类型别名

类型别名允许为现有类型定义一个新的名称。例如:

typealias IntList = List<Int>
val ints: IntList = listOf(1, 2, 3)

类型别名可以使代码更易读,特别是在处理复杂类型时。

密封类

密封类用于表示受限的类继承结构。密封类的所有子类必须在与密封类相同的文件中声明。密封类通常与 when 语句结合使用,以提供更安全和简洁的条件分支。

sealed class Result
class Success(val data: String) : Result()
class Failure(val errorMessage: String) : Result()

fun handleResult(result: Result) {
    when (result) {
        is Success -> println("Success: ${result.data}")
        is Failure -> println("Failure: ${result.errorMessage}")
    }
}

在上面的例子中,Result 是密封类,SuccessFailure 是它的子类。when 语句在处理 Result 类型时,编译器可以确保所有可能的子类型都被处理。

枚举类

枚举类用于定义一组命名的常量。例如:

enum class Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

枚举类可以有属性和方法。例如:

enum class Day(val index: Int) {
    MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7)
}

可以通过 Day.MONDAY.index 访问枚举常量的属性。

数组

Kotlin 中的数组由 Array 类表示。可以通过 arrayOf() 函数创建数组:

val numbers = arrayOf(1, 2, 3, 4, 5)

也可以创建特定类型的数组,例如 IntArray

val intArray = intArrayOf(1, 2, 3, 4, 5)

数组元素可以通过索引访问:

val firstNumber = numbers[0]

集合

Kotlin 提供了丰富的集合类型,包括列表(List)、集合(Set)和映射(Map)。

  1. 列表

    • 不可变列表:List 接口表示不可变列表,通过 listOf() 函数创建。
    val numbers = listOf(1, 2, 3, 4, 5)
    
    • 可变列表:MutableList 接口表示可变列表,通过 mutableListOf() 函数创建。
    val mutableNumbers = mutableListOf(1, 2, 3, 4, 5)
    mutableNumbers.add(6)
    
  2. 集合

    • 不可变集合:Set 接口表示不可变集合,通过 setOf() 函数创建。
    val uniqueNumbers = setOf(1, 2, 3, 3, 4, 5) // 集合会自动去除重复元素
    
    • 可变集合:MutableSet 接口表示可变集合,通过 mutableSetOf() 函数创建。
    val mutableUniqueNumbers = mutableSetOf(1, 2, 3)
    mutableUniqueNumbers.add(4)
    
  3. 映射

    • 不可变映射:Map 接口表示不可变映射,通过 mapOf() 函数创建。
    val nameAgeMap = mapOf("John" to 30, "Jane" to 25)
    
    • 可变映射:MutableMap 接口表示可变映射,通过 mutableMapOf() 函数创建。
    val mutableNameAgeMap = mutableMapOf("John" to 30)
    mutableNameAgeMap.put("Jane", 25)
    

Kotlin 的集合框架提供了丰富的操作函数,如过滤、映射、折叠等,使得对集合的操作更加方便和高效。例如:

val numbers = listOf(1, 2, 3, 4, 5)
val evenNumbers = numbers.filter { it % 2 == 0 }
val squaredNumbers = numbers.map { it * it }

通过深入了解 Kotlin 的基础语法和类型系统,开发者可以更加高效地编写 Kotlin 代码,充分发挥 Kotlin 在现代软件开发中的优势。无论是开发 Android 应用,还是服务器端应用,Kotlin 的简洁语法和强大的类型系统都能提供良好的编程体验。