Skip to content

数据类型

概述

Kotlin拥有丰富的类型系统,包括基本类型、集合类型、函数类型等。本章将详细介绍Kotlin的类型系统,包括类型推断、空安全、泛型等重要概念。

基本数据类型

数字类型

kotlin
fun main() {
    // 整数类型
    val byte: Byte = 127                    // 8位,-128到127
    val short: Short = 32767                // 16位,-32768到32767
    val int: Int = 2147483647              // 32位,-2^31到2^31-1
    val long: Long = 9223372036854775807L  // 64位,-2^63到2^63-1
    
    // 浮点类型
    val float: Float = 3.14f               // 32位IEEE 754
    val double: Double = 3.14159265359     // 64位IEEE 754
    
    println("整数类型:")
    println("Byte: $byte (${Byte.MIN_VALUE} to ${Byte.MAX_VALUE})")
    println("Short: $short (${Short.MIN_VALUE} to ${Short.MAX_VALUE})")
    println("Int: $int (${Int.MIN_VALUE} to ${Int.MAX_VALUE})")
    println("Long: $long (${Long.MIN_VALUE} to ${Long.MAX_VALUE})")
    
    println("\n浮点类型:")
    println("Float: $float")
    println("Double: $double")
}

数字类型转换

kotlin
fun main() {
    val int: Int = 42
    
    // 显式转换(Kotlin不支持隐式转换)
    val long: Long = int.toLong()
    val double: Double = int.toDouble()
    val float: Float = int.toFloat()
    val byte: Byte = int.toByte()
    
    println("原始值: $int")
    println("转换为Long: $long")
    println("转换为Double: $double")
    println("转换为Float: $float")
    println("转换为Byte: $byte")
    
    // 数字运算
    val a = 10
    val b = 3
    println("\n数字运算:")
    println("$a + $b = ${a + b}")
    println("$a - $b = ${a - b}")
    println("$a * $b = ${a * b}")
    println("$a / $b = ${a / b}")        // 整数除法
    println("$a % $b = ${a % b}")        // 取余
    println("$a / $b.0 = ${a / b.0}")   // 浮点除法
}

位运算

kotlin
fun main() {
    val a = 0b1010  // 10 in binary
    val b = 0b1100  // 12 in binary
    
    println("a = $a (${a.toString(2)})")
    println("b = $b (${b.toString(2)})")
    println()
    
    // 位运算操作
    println("a shl 1 = ${a shl 1} (${(a shl 1).toString(2)})")  // 左移
    println("a shr 1 = ${a shr 1} (${(a shr 1).toString(2)})")  // 右移
    println("a ushr 1 = ${a ushr 1}")                           // 无符号右移
    println("a and b = ${a and b} (${(a and b).toString(2)})")  // 按位与
    println("a or b = ${a or b} (${(a or b).toString(2)})")     // 按位或
    println("a xor b = ${a xor b} (${(a xor b).toString(2)})")  // 按位异或
    println("a.inv() = ${a.inv()} (${a.inv().toString(2)})")    // 按位取反
}

字符和字符串

字符类型

kotlin
fun main() {
    val char: Char = 'A'
    val digit: Char = '9'
    val unicode: Char = '\u0041'  // Unicode A
    
    println("字符: $char")
    println("数字字符: $digit")
    println("Unicode字符: $unicode")
    
    // 字符属性检查
    println("\n字符属性:")
    println("'$char' 是字母: ${char.isLetter()}")
    println("'$digit' 是数字: ${digit.isDigit()}")
    println("'$char' 是大写: ${char.isUpperCase()}")
    println("'$char' 转小写: ${char.lowercaseChar()}")
    
    // 字符转换
    if (digit.isDigit()) {
        val numericValue = digit.digitToInt()
        println("'$digit' 的数值: $numericValue")
    }
}

字符串类型

kotlin
fun main() {
    val str1 = "Hello, Kotlin!"
    val str2 = "World"
    
    // 字符串属性
    println("字符串长度: ${str1.length}")
    println("第一个字符: ${str1[0]}")
    println("最后一个字符: ${str1[str1.length - 1]}")
    
    // 字符串方法
    println("\n字符串方法:")
    println("大写: ${str1.uppercase()}")
    println("小写: ${str1.lowercase()}")
    println("包含'Kotlin': ${str1.contains("Kotlin")}")
    println("以'Hello'开头: ${str1.startsWith("Hello")}")
    println("以'!'结尾: ${str1.endsWith("!")}")
    
    // 字符串操作
    println("\n字符串操作:")
    println("连接: ${str1 + " " + str2}")
    println("替换: ${str1.replace("Kotlin", "World")}")
    println("子字符串: ${str1.substring(0, 5)}")
    println("分割: ${str1.split(" ")}")
    
    // 字符串模板
    val name = "Alice"
    val age = 25
    println("\n字符串模板:")
    println("姓名: $name, 年龄: $age")
    println("明年年龄: ${age + 1}")
    println("姓名长度: ${name.length}")
}

原始字符串和转义

kotlin
fun main() {
    // 转义字符串
    val escaped = "第一行\n第二行\t制表符\\"反斜杠\\""
    println("转义字符串:")
    println(escaped)
    
    // 原始字符串(三重引号)
    val raw = """
        |这是原始字符串
        |可以包含换行符
        |和"引号"而无需转义
        |反斜杠 \ 也是字面量
        |${1 + 1} 仍然会被处理
    """.trimMargin()
    
    println("\n原始字符串:")
    println(raw)
    
    // 不处理模板的原始字符串
    val rawNoTemplate = """
        不处理模板: ${'$'}{1 + 1}
        使用 ${'$'}{'$'} 来输出字面量 $
    """.trimIndent()
    
    println("\n不处理模板的原始字符串:")
    println(rawNoTemplate)
}

布尔类型

kotlin
fun main() {
    val isTrue: Boolean = true
    val isFalse: Boolean = false
    
    // 布尔运算
    println("布尔运算:")
    println("true && false = ${true && false}")   // 逻辑与
    println("true || false = ${true || false}")   // 逻辑或
    println("!true = ${!true}")                   // 逻辑非
    
    // 短路求值
    fun expensiveOperation(): Boolean {
        println("执行昂贵操作")
        return true
    }
    
    println("\n短路求值:")
    println("false && expensiveOperation() = ${false && expensiveOperation()}")  // 不会执行
    println("true || expensiveOperation() = ${true || expensiveOperation()}")    // 不会执行
}

数组

基本数组

kotlin
fun main() {
    // 创建数组
    val numbers = arrayOf(1, 2, 3, 4, 5)
    val strings = arrayOf("apple", "banana", "cherry")
    val mixed = arrayOf(1, "hello", 3.14, true)  // Any类型数组
    
    // 指定类型的数组
    val integers: Array<Int> = arrayOf(1, 2, 3)
    val nullableStrings: Array<String?> = arrayOfNulls(5)
    
    // 使用构造函数创建数组
    val squares = Array(5) { i -> i * i }  // [0, 1, 4, 9, 16]
    
    println("数组内容:")
    println("numbers: ${numbers.contentToString()}")
    println("strings: ${strings.contentToString()}")
    println("squares: ${squares.contentToString()}")
    
    // 数组访问和修改
    println("\n数组操作:")
    println("第一个元素: ${numbers[0]}")
    println("数组长度: ${numbers.size}")
    
    numbers[0] = 10
    println("修改后: ${numbers.contentToString()}")
    
    // 数组遍历
    println("\n数组遍历:")
    for (number in numbers) {
        print("$number ")
    }
    println()
    
    for ((index, value) in numbers.withIndex()) {
        println("索引 $index: $value")
    }
}

原始类型数组

kotlin
fun main() {
    // 原始类型数组(避免装箱开销)
    val intArray = intArrayOf(1, 2, 3, 4, 5)
    val doubleArray = doubleArrayOf(1.1, 2.2, 3.3)
    val booleanArray = booleanArrayOf(true, false, true)
    val charArray = charArrayOf('a', 'b', 'c')
    
    println("原始类型数组:")
    println("IntArray: ${intArray.contentToString()}")
    println("DoubleArray: ${doubleArray.contentToString()}")
    println("BooleanArray: ${booleanArray.contentToString()}")
    println("CharArray: ${charArray.contentToString()}")
    
    // 数组操作
    println("\n数组操作:")
    println("求和: ${intArray.sum()}")
    println("平均值: ${intArray.average()}")
    println("最大值: ${intArray.maxOrNull()}")
    println("最小值: ${intArray.minOrNull()}")
    
    // 数组转换
    val doubled = intArray.map { it * 2 }
    val filtered = intArray.filter { it > 2 }
    
    println("翻倍: $doubled")
    println("过滤 > 2: $filtered")
}

集合类型

列表 (List)

kotlin
fun main() {
    // 不可变列表
    val readOnlyList = listOf("apple", "banana", "cherry")
    val emptyList = emptyList<String>()
    val listWithNulls = listOfNotNull("apple", null, "banana", null)
    
    // 可变列表
    val mutableList = mutableListOf("kotlin", "java", "python")
    val arrayList = arrayListOf<String>()
    
    println("列表操作:")
    println("只读列表: $readOnlyList")
    println("去除null的列表: $listWithNulls")
    
    // 列表操作
    mutableList.add("javascript")
    mutableList.remove("java")
    mutableList[0] = "Kotlin"  // 修改元素
    
    println("可变列表: $mutableList")
    
    // 列表方法
    println("\n列表方法:")
    println("大小: ${readOnlyList.size}")
    println("是否为空: ${readOnlyList.isEmpty()}")
    println("包含'apple': ${readOnlyList.contains("apple")}")
    println("第一个元素: ${readOnlyList.first()}")
    println("最后一个元素: ${readOnlyList.last()}")
    println("获取索引1: ${readOnlyList.getOrNull(1)}")
    
    // 列表转换
    val fruits = listOf("apple", "banana", "cherry")
    val upperCaseFruits = fruits.map { it.uppercase() }
    val longFruits = fruits.filter { it.length > 5 }
    val totalLength = fruits.sumOf { it.length }
    
    println("\n列表转换:")
    println("大写: $upperCaseFruits")
    println("长度>5: $longFruits")
    println("总长度: $totalLength")
}

集合 (Set)

kotlin
fun main() {
    // 不可变集合
    val readOnlySet = setOf("apple", "banana", "apple")  // 重复元素会被去除
    val emptySet = emptySet<String>()
    
    // 可变集合
    val mutableSet = mutableSetOf("kotlin", "java", "python")
    val hashSet = hashSetOf<String>()
    val linkedHashSet = linkedSetOf<String>()  // 保持插入顺序
    
    println("集合操作:")
    println("只读集合: $readOnlySet")  // [apple, banana]
    println("集合大小: ${readOnlySet.size}")
    
    // 集合操作
    mutableSet.add("javascript")
    mutableSet.add("kotlin")  // 重复元素不会被添加
    mutableSet.remove("java")
    
    println("可变集合: $mutableSet")
    
    // 集合运算
    val set1 = setOf(1, 2, 3, 4)
    val set2 = setOf(3, 4, 5, 6)
    
    println("\n集合运算:")
    println("set1: $set1")
    println("set2: $set2")
    println("并集: ${set1 union set2}")
    println("交集: ${set1 intersect set2}")
    println("差集: ${set1 - set2}")
    
    // 集合检查
    println("\n集合检查:")
    println("set1包含2: ${2 in set1}")
    println("set1包含所有[1,2]: ${set1.containsAll(listOf(1, 2))}")
}

映射 (Map)

kotlin
fun main() {
    // 不可变映射
    val readOnlyMap = mapOf(
        "name" to "Kotlin",
        "version" to "1.9",
        "type" to "Programming Language"
    )
    
    val emptyMap = emptyMap<String, String>()
    
    // 可变映射
    val mutableMap = mutableMapOf<String, Int>()
    val hashMap = hashMapOf<String, String>()
    val linkedHashMap = linkedMapOf<String, String>()  // 保持插入顺序
    
    println("映射操作:")
    println("只读映射: $readOnlyMap")
    
    // 映射操作
    mutableMap["apple"] = 5
    mutableMap["banana"] = 3
    mutableMap["cherry"] = 8
    mutableMap.put("date", 2)  // 等同于 mutableMap["date"] = 2
    
    println("可变映射: $mutableMap")
    
    // 映射访问
    println("\n映射访问:")
    println("apple的数量: ${mutableMap["apple"]}")
    println("grape的数量: ${mutableMap["grape"]}")  // null
    println("grape的数量(默认值): ${mutableMap.getOrDefault("grape", 0)}")
    println("所有键: ${mutableMap.keys}")
    println("所有值: ${mutableMap.values}")
    
    // 映射遍历
    println("\n映射遍历:")
    for ((fruit, count) in mutableMap) {
        println("$fruit: $count")
    }
    
    // 映射转换
    val doubled = mutableMap.mapValues { (_, value) -> value * 2 }
    val filtered = mutableMap.filter { (_, value) -> value > 3 }
    
    println("\n映射转换:")
    println("翻倍: $doubled")
    println("过滤>3: $filtered")
}

可空类型

可空性基础

kotlin
fun main() {
    // 非空类型
    var name: String = "Kotlin"
    // name = null  // 编译错误
    
    // 可空类型
    var nullableName: String? = "Kotlin"
    nullableName = null  // 允许
    
    println("非空类型: $name")
    println("可空类型: $nullableName")
    
    // 安全调用操作符 ?.
    println("安全调用长度: ${nullableName?.length}")
    
    // Elvis操作符 ?:
    val length = nullableName?.length ?: 0
    println("长度(默认值): $length")
    
    // 非空断言 !!
    nullableName = "Kotlin"
    println("非空断言长度: ${nullableName!!.length}")  // 谨慎使用
    
    // 安全转换 as?
    val obj: Any = "Hello"
    val str: String? = obj as? String
    val int: Int? = obj as? Int  // null,因为转换失败
    
    println("安全转换String: $str")
    println("安全转换Int: $int")
}

可空性处理模式

kotlin
// 处理可空参数
fun processName(name: String?) {
    // 方式1: 使用if检查
    if (name != null) {
        println("处理姓名: ${name.uppercase()}")  // 智能转换
    } else {
        println("姓名为空")
    }
    
    // 方式2: 使用let
    name?.let { 
        println("使用let处理: ${it.uppercase()}")
    }
    
    // 方式3: 使用Elvis操作符
    val processedName = name?.uppercase() ?: "UNKNOWN"
    println("处理后的姓名: $processedName")
}

// 返回可空值的函数
fun findUser(id: Int): User? {
    return if (id > 0) User("User$id") else null
}

data class User(val name: String)

fun main() {
    processName("alice")
    processName(null)
    
    val user = findUser(1)
    val invalidUser = findUser(-1)
    
    println("找到用户: ${user?.name}")
    println("无效用户: ${invalidUser?.name}")
}

类型检查和转换

类型检查

kotlin
fun main() {
    val items = listOf("hello", 42, 3.14, true, null)
    
    for (item in items) {
        when (item) {
            is String -> println("字符串: '$item', 长度: ${item.length}")
            is Int -> println("整数: $item, 平方: ${item * item}")
            is Double -> println("浮点数: $item, 四舍五入: ${item.toInt()}")
            is Boolean -> println("布尔值: $item, 取反: ${!item}")
            null -> println("空值")
            else -> println("未知类型: $item")
        }
    }
}

类型转换

kotlin
fun main() {
    val obj: Any = "Hello, Kotlin!"
    
    // 不安全转换 as
    try {
        val str = obj as String
        println("转换成功: $str")
        
        // val int = obj as Int  // 会抛出ClassCastException
    } catch (e: ClassCastException) {
        println("转换失败: ${e.message}")
    }
    
    // 安全转换 as?
    val str: String? = obj as? String
    val int: Int? = obj as? Int
    
    println("安全转换String: $str")
    println("安全转换Int: $int")
    
    // 智能转换
    if (obj is String) {
        // 在这个作用域内,obj被智能转换为String
        println("智能转换: ${obj.uppercase()}")
    }
}

泛型基础

泛型类和函数

kotlin
// 泛型类
class Box<T>(val value: T) {
    fun get(): T = value
    
    override fun toString(): String = "Box($value)"
}

// 泛型函数
fun <T> identity(value: T): T = value

fun <T> swap(pair: Pair<T, T>): Pair<T, T> = Pair(pair.second, pair.first)

// 多个类型参数
fun <K, V> createMap(key: K, value: V): Map<K, V> = mapOf(key to value)

fun main() {
    // 使用泛型类
    val stringBox = Box("Hello")
    val intBox = Box(42)
    
    println("字符串盒子: $stringBox")
    println("整数盒子: $intBox")
    
    // 使用泛型函数
    val str = identity("Kotlin")
    val num = identity(100)
    
    println("Identity字符串: $str")
    println("Identity数字: $num")
    
    // 交换对
    val originalPair = Pair("first", "second")
    val swappedPair = swap(originalPair)
    
    println("原始对: $originalPair")
    println("交换后: $swappedPair")
    
    // 创建映射
    val map = createMap("language", "Kotlin")
    println("创建的映射: $map")
}

类型约束

kotlin
// 上界约束
fun <T : Number> sum(a: T, b: T): Double {
    return a.toDouble() + b.toDouble()
}

// 多个约束
interface Printable {
    fun print()
}

class Document : Printable {
    override fun print() = println("打印文档")
}

fun <T> process(item: T) where T : Printable, T : Comparable<T> {
    item.print()
    // 可以使用Printable和Comparable的方法
}

fun main() {
    // 使用约束的泛型函数
    val intSum = sum(10, 20)
    val doubleSum = sum(3.14, 2.86)
    
    println("整数求和: $intSum")
    println("浮点数求和: $doubleSum")
    
    // sum("hello", "world")  // 编译错误:String不是Number的子类型
}

类型别名

kotlin
// 为复杂类型创建别名
typealias UserMap = Map<String, User>
typealias StringProcessor = (String) -> String
typealias EventHandler<T> = (T) -> Unit

// 为泛型类创建别名
typealias StringBox = Box<String>

data class User(val name: String, val email: String)

fun main() {
    // 使用类型别名
    val users: UserMap = mapOf(
        "1" to User("Alice", "alice@example.com"),
        "2" to User("Bob", "bob@example.com")
    )
    
    val processor: StringProcessor = { it.uppercase() }
    val eventHandler: EventHandler<String> = { println("事件: $it") }
    
    println("用户映射: $users")
    println("处理结果: ${processor("hello")}")
    eventHandler("按钮点击")
    
    // 使用泛型类型别名
    val stringBox: StringBox = Box("Hello")
    println("字符串盒子: $stringBox")
}

最佳实践

1. 空安全

kotlin
// 好的做法:使用安全调用和Elvis操作符
fun processUser(user: User?) {
    val name = user?.name ?: "Unknown"
    val email = user?.email?.lowercase() ?: "no-email"
    println("用户: $name, 邮箱: $email")
}

// 避免过度使用非空断言
fun badExample(user: User?) {
    // 不好:过度使用!!
    // println("用户: ${user!!.name}, 邮箱: ${user!!.email}")
}

2. 集合选择

kotlin
// 根据需求选择合适的集合类型
fun main() {
    // 需要保持顺序且允许重复:List
    val orderItems = listOf("item1", "item2", "item1")
    
    // 需要唯一性:Set
    val uniqueIds = setOf("id1", "id2", "id3")
    
    // 需要键值映射:Map
    val userPreferences = mapOf("theme" to "dark", "language" to "en")
    
    // 需要频繁修改:使用可变版本
    val mutableItems = mutableListOf<String>()
}

3. 泛型使用

kotlin
// 使用泛型提高代码复用性
class Repository<T> {
    private val items = mutableListOf<T>()
    
    fun add(item: T) = items.add(item)
    fun getAll(): List<T> = items.toList()
    fun find(predicate: (T) -> Boolean): T? = items.find(predicate)
}

// 使用类型约束确保类型安全
fun <T : Comparable<T>> findMax(items: List<T>): T? {
    return items.maxOrNull()
}

下一步

了解了Kotlin的数据类型系统后,让我们学习变量和常量的声明与使用。

下一章: 变量和常量

练习题

  1. 创建一个程序展示所有基本数据类型的使用和转换
  2. 实现一个安全的除法函数,处理除零和空值情况
  3. 设计一个泛型的缓存类,支持不同类型的数据存储
  4. 编写函数来演示集合的各种操作(过滤、映射、聚合等)
  5. 创建一个类型安全的配置管理器,使用类型别名和泛型

本站内容仅供学习和研究使用。