Kotlin 学习笔记-数据类型

41 阅读5分钟

一、Boolean

Kotlin中的Boolean类型只有两个值:truefalse。布尔类型主要用于条件判断和控制流。

val isTrue: Boolean = true
val isFalse: Boolean = false

// 示例:条件判断
if (isTrue) {
    println("This is true")
} else {
    println("This is false")
}

二、Number

Kotlin中的数值类型包含整数类型和浮点数类型,分别有以下几种:

  • Byte: 8位
  • Short: 16位
  • Int: 32位
  • Long: 64位
  • Float: 32位
  • Double: 64位
val byte: Byte = 1
val short: Short = 1
val int: Int = 1
val long: Long = 1L
val float: Float = 1.0f
val double: Double = 1.0

// 示例:基本运算
val sum = int + long.toInt()
val product = float * double

三、拆箱与装箱、Char

自动装箱和拆箱:Kotlin 编译器会在需要时自动进行装箱和拆箱。例如,当需要将 Int 传递给需要 Any 类型参数的函数时,Kotlin 会自动将其装箱为 Integer 对象。

fun printAny(any: Any) {
    println(any)
}

val num: Int = 5
printAny(num) // 自动装箱,将 Int 转换为 Integer 对象

数字类型的统一处理: 在Kotlin中,所有数字类型(如Int、Float等)都是对象,Kotlin会自动进行装箱和拆箱,不需要显式处理。

//由于 Kotlin 将数字类型作为对象处理,因此我们可以直接调用对象的方法和属性,而不需要显式进行装箱或拆箱。
val num: Int = 5
val doubled = num.times(2) // 调用对象的方法
println(doubled) // 输出 10

Char类型表示一个字符,使用单引号括起来。char.codeChar 类型的扩展属性,返回该字符的整数表示(Unicode 码点)

val char: Char = 'A'

// 示例:Char的操作
val nextChar = (char.code + 1).toChar()
println(nextChar) // 输出 'B'

四、基础数据类型转换与数组

数据类型转换使用显式转换函数,如toInt()toLong()toFloat()等。数组用arrayOf()创建。

val intVal: Int = 1
val longVal: Long = intVal.toLong()

// 示例:数组
val intArray = arrayOf(1, 2, 3)
val strArray = arrayOf("A", "B", "C")
val doubleArray = doubleArrayOf(1.0, 2.0, 3.0)

// 使用 for 循环遍历数组
for (item in intArray) {
    println(item)
}

// 使用 forEach 遍历数组
intArray.forEach { item -> 
    println(item)
}

4.1 常用的数组操作

Kotlin 提供了许多便捷的数组操作方法,如 mapfilterreduce 等。

假设我们有以下 intArray:

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

map 操作:将数组中的每个元素进行变换。

val squaredArray = intArray.map { it * it }
println(squaredArray) // 输出 [1, 4, 9, 16, 25]

filter 操作:过滤数组中的元素。

val evenArray = intArray.filter { it % 2 == 0 }
println(evenArray) // 输出 [2, 4]

reduce 操作:将数组中的元素进行归约操作。

val sum = intArray.reduce { acc, i -> acc + i }
println(sum) // 输出 15

4.2 数组的初始化

可以使用 Array 构造函数进行数组的初始化,通过指定数组大小和初始化表达式来创建数组。

val array = Array(5) { i -> i * 2 } //i是数组下标,表达式的返回值(最后一行)就是对应下标的值
println(array.joinToString()) // 输出 0, 2, 4, 6, 8

五、类和对象

在 Kotlin 中,类和对象是面向对象编程的核心。Kotlin 提供了比 Java 更简洁和强大的类和对象机制。

5.1 定义类

在 Kotlin 中,类的定义非常简单。下面是一个基本的类定义示例:

class Person(val name: String, var age: Int) {
    fun greet() {
        println("Hello, my name is $name and I am $age years old.")
    }
}

// 创建对象
val person = Person("John", 25)
person.greet()

5.2 主构造函数和次构造函数

Kotlin 提供了主构造函数和次构造函数,可以在类定义时同时初始化属性。

class Person(val name: String, var age: Int) {
    init {
        println("Person is created with name $name and age $age")
    }

    constructor(name: String) : this(name, 0) {
        println("Person is created with name $name and default age 0")
    }
}

5.3 属性和方法

类中的属性可以有默认值,也可以有自定义的 getter 和 setter 方法。

class Person {
    var name: String = "Unknown"
    var age: Int = 0
        set(value) {
            if (value > 0) field = value
        }

    fun greet() {
        println("Hello, my name is $name and I am $age years old.")
    }
}

val person = Person()
person.name = "Alice"
person.age = -2
person.greet() //输出 Hello, my name is Alice and I am 0 years old.

5.4 继承

Kotlin 中的类默认是 final 的,不能被继承。要允许继承,必须使用 open 关键字。

open class Animal(val name: String) {
    open fun sound() {
        println("$name makes a sound")
    }
}

class Dog(name: String) : Animal(name) {
    override fun sound() {
        println("$name barks")
    }
}

val dog = Dog("Buddy")
dog.sound() // 输出 "Buddy barks"

5.5 抽象类和接口

Kotlin 支持抽象类和接口。抽象类不能被实例化,可以包含抽象方法和具体方法。接口只能包含抽象方法(可以有默认实现)。

abstract class Animal(val name: String) {
    abstract fun sound()
}

class Dog(name: String) : Animal(name) {
    override fun sound() {
        println("$name barks")
    }
}

interface Pet {
    fun play()
}

class Cat(name: String) : Animal(name), Pet {
    override fun sound() {
        println("$name meows")
    }

    override fun play() {
        println("$name plays with a ball of yarn")
    }
}

val cat = Cat("Whiskers")
cat.sound() // 输出 "Whiskers meows"
cat.play()  // 输出 "Whiskers plays with a ball of yarn"

5.6 数据类

数据类用于只包含数据的类,自动生成常用的方法,如 toString()equals()hashCode()copy() 等。

data class User(val name: String, val age: Int)

val user1 = User("Alice", 30)
val user2 = user1.copy(name = "Bob")

println(user1) // 输出 "User(name=Alice, age=30)"
println(user2) // 输出 "User(name=Bob, age=30)"

5.7 单例对象

Kotlin 使用 object 关键字来声明单例对象,保证一个类只有一个实例。

object Database {
    fun connect() {
        println("Database connected")
    }
}

Database.connect() // 输出 "Database connected"

六、空类型和智能类型转换

Kotlin有安全的空类型处理,通过?!!操作符避免空指针异常。

val nullableString: String? = null

// 安全调用操作符
println(nullableString?.length) // 输出 null

// 非空断言操作符
println(nullableString!!.length) // 可能抛出NullPointerException

// 智能类型转换
if (nullableString != null) {
    println(nullableString.length) // 此处的nullableString被自动转换为非空类型
}

七、包

7.1 顶层函数与属性

Kotlin 允许在文件中定义顶层函数和属性,这些顶层元素可以直接在包中使用,而无需创建类。

package com.example.utilities

fun greet(name: String) {
    println("Hello, $name!")
}

val appName: String = "MyApp"
  • 编译后的处理:顶层函数和属性在编译后会被包装到一个与文件名对应的类中,类名为文件名加上 Kt 后缀。

  • 静态成员:编译后的类将顶层函数和属性作为静态方法和静态属性处理。

7.2 内部包与访问控制

Kotlin 支持嵌套包(内部包),并提供了访问控制机制,包括 publicprivateprotectedinternal

package com.example.myapp.internal

internal fun internalFunction() {
    println("This is an internal function")
}

private fun privateFunction() {
    println("This is a private function")
}
  • public:默认访问修饰符,任何地方都可以访问。

  • private:仅在声明它的文件中可见。

  • protected:不能用于顶层声明,只能用于类成员。

  • internal:在同一个模块中可见。

7.3 多重导入

如果导入的类或函数名称冲突,可以使用 as 关键字进行重命名。

import com.example.package1.functionA
import com.example.package2.functionA as functionB

fun main() {
    functionA()
    functionB()
}

八、区间

8.1 基本语法

区间表示连续的值范围,用于迭代和条件判断。Kotlin的整数区间支持 step 操作符来指定步长。

val range = 1..10

for (i in range) {
    println(i)
}

// 使用 step 指定步长
val stepRange = 1..10 step 2

for (i in stepRange) {
    println(i) // 输出 1, 3, 5, 7, 9
}

// 检查值是否在区间内
val inRange = 5 in range // true

8.2 浮点数区间与步长

浮点数没有直接的区间与步长支持,可以使用生成序列来实现类似功能。

fun floatRange(start: Float, end: Float, step: Float): Sequence<Float> {
    require(step > 0) { "Step must be positive" }
    return generateSequence(start) { previous ->
        val next = previous + step
        if (next <= end) next else null
    }
}

val floatSeq = floatRange(1.0f, 5.0f, 0.5f)

for (value in floatSeq) {
    println(value) // 输出 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0
}