Kotlin 教程
Kotlin 教程
Kotlin 是由 JetBrains 开发的现代化静态类型编程语言,2017 年被 Google 指定为 Android 官方开发语言,也可用于后端、Web、桌面与多平台开发。它运行在 JVM 之上,与 Java 100% 互操作,同时吸收了函数式编程与空安全等现代语言特性。
为什么选择 Kotlin?
- 简洁:代码量比 Java 平均减少约 40%,没有样板代码(如 getter/setter、构造函数模板)
- 安全:内置空安全机制,编译期即消除大量空指针异常
- 互操作:可直接调用现有 Java 库,与 Java 代码无缝混编
- 多平台:一套代码可编译为 JVM、JavaScript 与原生二进制
学习路线
- 环境搭建(IntelliJ IDEA / Eclipse / 命令行)
- 基础语法与数据类型
- 条件与循环控制
- 面向对象:类、继承、接口、扩展、数据类
- 高级特性:泛型、枚举、对象表达式、委托
第一个程序
fun main() {
println("Hello, Kotlin!")
}
无需分号,无需 main 类,直接函数即入口,这是 Kotlin 简洁性的第一印象。
接下来我们将从环境搭建开始,一步步掌握这门语言。
Kotlin IntelliJ IDEA 环境搭建
Kotlin IntelliJ IDEA 环境搭建
IntelliJ IDEA 是 JetBrains 官方 IDE,对 Kotlin 支持最完善,是 Kotlin 开发的首选工具。
1. 安装 JDK
Kotlin 运行在 JVM 上,需要先安装 JDK(建议 JDK 8 或更高版本):
# macOS brew install openjdk # Ubuntu sudo apt install openjdk-11-jdk # 验证 java -version
2. 下载安装 IntelliJ IDEA
- 访问 JetBrains 官网下载 Community(免费)或 Ultimate(付费)版本
- 安装完成后打开,选择 New Project
3. 创建 Kotlin 项目
- File → New → Project
- 选择 Kotlin 分类,语言选 Kotlin,构建系统选 Gradle 或 IntelliJ
- 选择 JDK 版本,点击 Finish
4. 编写并运行
fun main() {
println("Hello from IntelliJ!")
}
右键 main 函数 → Run,即可在控制台看到输出。IDEA 内置的 Kotlin 插件已自动启用,无需额外配置。
常用快捷键
Shift+F10:运行当前文件Alt+Enter:快速修复/补全Cmd/Ctrl+N:查找类
Kotlin Eclipse 环境搭建
Kotlin Eclipse 环境搭建
如果习惯使用 Eclipse,也可以通过安装 Kotlin 插件进行开发。
1. 安装插件
- 打开 Eclipse → Help → Eclipse Marketplace
- 搜索 Kotlin,找到 JetBrains 提供的 Kotlin Plugin
- 点击 Install,重启 Eclipse
2. 创建 Kotlin 项目
- File → New → Project
- 选择 Kotlin Project
- 右键 src 目录 → New → Kotlin File
3. 配置 Kotlin 编译器
Eclipse 插件会自动管理 Kotlin 编译器与运行时,右键项目 → Properties → Kotlin Compiler,可查看/修改编译选项:
jvmTarget = 1.8 languageVersion = 1.9 apiVersion = 1.9
4. 运行
fun main() {
println("Kotlin on Eclipse!")
}
右键文件 → Run As → Kotlin Application,即可看到输出。
提示:Eclipse 对 Kotlin 的支持不如 IntelliJ 完善,建议大型项目使用 IntelliJ IDEA。
Kotlin 使用命令行编译
Kotlin 使用命令行编译
不依赖 IDE,仅通过命令行即可编译运行 Kotlin 程序,适合脚本化与 CI 环境。
1. 安装 Kotlin 命令行编译器
# macOS (Homebrew) brew install kotlin # SDKMAN curl -s "https://get.sdkman.io" | bash sdk install kotlin # 验证 kotlinc -version
2. 编写源文件
创建 hello.kt:
fun main() {
println("Hello, Kotlin CLI!")
}
3. 编译运行
# 编译为 JVM 字节码 kotlinc hello.kt -include-runtime -d hello.jar # 运行 java -jar hello.jar # 或者直接运行脚本 kotlinc -script hello.kt
4. 编译多个文件
kotlinc file1.kt file2.kt -include-runtime -d app.jar java -jar app.jar
5. 与 Maven/Gradle 配合
实际项目中建议用构建工具管理依赖,在 build.gradle.kts 中:
plugins {
kotlin("jvm") version "1.9.0"
}
命令行方式适合快速验证与学习,生产项目推荐 Gradle。
Kotlin Android 环境搭建
Kotlin Android 环境搭建
Kotlin 是 Android 官方推荐语言,Android Studio 内置完整支持。
1. 安装 Android Studio
- 从官网下载 Android Studio
- 安装时勾选 Android SDK 组件
- 创建第一个项目时,语言选择 Kotlin
2. 项目结构
app/ ├── src/main/java/com/example/app/ │ └── MainActivity.kt └── build.gradle.kts
3. 编写 Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<TextView>(R.id.tvHello).text = "Hello Kotlin!"
}
}
4. 布局文件
<TextView
android:id="@+id/tvHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
5. 运行调试
- 连接设备或启动模拟器
- 点击 Run 按钮(绿色三角)
- 使用 Logcat 查看日志、断点调试
6. 常用库
- Jetpack Compose:现代声明式 UI 框架
- Coroutines:协程处理异步任务
- Retrofit:网络请求
Kotlin 基础语法
Kotlin 基础语法
1. 包声明与导入
package com.example.demo
import java.util.Date
fun main() {
println(Date())
}
2. 变量声明
Kotlin 用 val(不可变)与 var(可变)声明变量,类型可自动推断:
val name = "Kotlin" // 字符串,不可重新赋值 var age = 10 // 整数,可变 val price: Double = 19.9 // 显式指定类型 age = 11 // 允许
3. 函数定义
// 传统写法
fun sum(a: Int, b: Int): Int {
return a + b
}
// 表达式函数体
fun sum2(a: Int, b: Int) = a + b
// 默认参数
fun greet(name: String = "World") = "Hello, $name"
4. 字符串模板
val name = "Kotlin"
println("Hello, $name!") // Hello, Kotlin!
println("长度: ${name.length}") // 长度: 6
5. 注释
// 单行注释 /* 多行 注释 */ /** KDoc 文档注释 */
6. 空安全
var s: String? = null // 可空类型 println(s?.length) // 安全调用,输出 null println(s?.length ?: 0) // Elvis 运算符,输出 0 // s!!.length // 强制非空,可能抛异常
Kotlin 基本数据类型
Kotlin 基本数据类型
1. 数值类型
val b: Byte = 127 val s: Short = 32767 val i: Int = 2147483647 val l: Long = 9223372036854775807L val f: Float = 3.14F val d: Double = 3.1415926 val hex = 0x0F // 十六进制 val bin = 0b1010 // 二进制
2. 布尔与字符
val flag: Boolean = true val c: Char = 'A' val esc = '\n' // 转义字符 val unicode = '\uFF00'
3. 类型转换
Kotlin 不允许隐式转换,必须显式调用:
val i = 100 val l = i.toLong() val d = i.toDouble() val s = i.toString() val back = s.toInt()
4. 位运算
val a = 0b1100 val b = 0b1010 println(a and b) // 8 与 println(a or b) // 14 或 println(a xor b) // 6 异或 println(a shl 1) // 24 左移 println(a shr 1) // 6 右移
5. 字符串
val s = "Hello" println(s[0]) // H println(s.length) // 5 println(s.uppercase()) // HELLO // 原始字符串 val raw = """多行 字符串内容""" println(raw)
6. 数组
val arr = intArrayOf(1, 2, 3)
val list = arrayOf("a", "b", "c")
println(arr[0])
println(arr.size)
Kotlin 条件控制
Kotlin 条件控制
1. if 表达式
Kotlin 的 if 是表达式,可直接返回值:
val a = 10
val b = 20
// 传统用法
var max = a
if (a < b) max = b
// 表达式用法
val max2 = if (a > b) a else b
// 多分支
val grade = if (score >= 90) "A"
else if (score >= 80) "B"
else if (score >= 70) "C"
else "D"
2. when 表达式
when 替代 Java 的 switch,更强大:
fun describe(x: Any): String = when (x) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long number"
!is String -> "Not a string"
else -> "Unknown"
}
// when 分支可以用区间
fun score(s: Int) = when (s) {
in 90..100 -> "优秀"
in 80..89 -> "良好"
in 60..79 -> "及格"
else -> "不及格"
}
// when 不带参数
fun isWeekend(day: String) = when {
day == "周六" || day == "周日" -> true
else -> false
}
3. 区间
val r1 = 1..10 // 1 到 10(含) val r2 = 1 until 10 // 1 到 9(不含10) val r3 = 10 downTo 1 // 10 到 1 递减 val r4 = 1..10 step 2 // 1,3,5,7,9
Kotlin 循环控制
Kotlin 循环控制
1. for 循环
// 遍历区间
for (i in 1..5) {
println(i)
}
// 遍历数组
val arr = arrayOf("a", "b", "c")
for (item in arr) {
println(item)
}
// 带索引
for ((index, value) in arr.withIndex()) {
println("$index -> $value")
}
// 指定步长与倒序
for (i in 10 downTo 1 step 2) {
println(i)
}
2. while 循环
var i = 0
while (i < 5) {
println("i = $i")
i++
}
var j = 0
do {
println("至少执行一次: $j")
j++
} while (j < 3)
3. break 与 continue
for (i in 1..10) {
if (i == 3) continue // 跳过 3
if (i == 8) break // 到 8 退出
println(i)
}
// 标签跳出外层循环
outer@ for (i in 1..3) {
for (j in 1..3) {
if (j == 2) break@outer
println("$i-$j")
}
}
4. 遍历集合
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Kotlin 类和对象
Kotlin 类和对象
1. 类定义
class Person {
var name: String = ""
var age: Int = 0
fun speak() {
println("$name 在说话")
}
}
val p = Person()
p.name = "张三"
p.age = 25
p.speak()
2. 构造函数
// 主构造函数
class User(val name: String, var age: Int) {
// 初始化块
init {
println("User 创建: $name")
}
// 次构造函数
constructor(name: String) : this(name, 0)
}
val u1 = User("李四", 30)
val u2 = User("王五")
3. 属性与 getter/setter
class Circle(radius: Double) {
var radius = radius
get() = field
set(value) {
if (value > 0) field = value
}
val area: Double
get() = 3.14159 * radius * radius
}
4. 可见性修饰符
public(默认):所有地方可见private:类内可见protected:类及子类可见internal:模块内可见
5. 伴生对象
class MathUtil {
companion object {
const val PI = 3.14159
fun square(x: Double) = x * x
}
}
println(MathUtil.PI)
println(MathUtil.square(4.0))
Kotlin 继承
Kotlin 继承
Kotlin 中所有类默认是 final 的,必须用 open 关键字标记才能被继承。
1. 定义可继承的类
open class Animal(val name: String) {
// open 方法才能被重写
open fun sound() {
println("$name 发出声音")
}
}
2. 继承与重写
class Dog(name: String) : Animal(name) {
override fun sound() {
println("$name 汪汪叫")
}
}
class Cat(name: String) : Animal(name) {
override fun sound() {
super.sound() // 调用父类实现
println("$name 喵喵叫")
}
}
val d = Dog("旺财")
d.sound() // 旺财 汪汪叫
3. 抽象类
abstract class Shape {
abstract fun area(): Double
fun describe() = "面积是 ${area()}"
}
class Square(val side: Double) : Shape() {
override fun area() = side * side
}
4. 多态
val animals: List<Animal> = listOf(Dog("A"), Cat("B"))
for (a in animals) {
a.sound() // 运行时动态分派
}
5. 属性重写
open class Base {
open val value: Int = 10
}
class Derived : Base() {
override val value: Int = 20
}
Kotlin 接口
Kotlin 接口
Kotlin 接口可以包含抽象方法、带默认实现的方法和属性声明。
1. 定义接口
interface Flyable {
// 抽象方法
fun fly()
// 带默认实现
fun land() {
println("正在降落...")
}
// 属性(接口中只能声明,不能初始化)
val maxSpeed: Int
}
2. 实现接口
class Bird : Flyable {
override val maxSpeed = 100
override fun fly() {
println("小鸟在飞,速度 $maxSpeed")
}
}
val b = Bird()
b.fly()
b.land() // 使用默认实现
3. 多接口实现
interface A {
fun foo() { println("A.foo") }
}
interface B {
fun foo() { println("B.foo") }
}
class C : A, B {
// 冲突时必须手动指定
override fun foo() {
super<A>.foo()
super<B>.foo()
}
}
4. 接口继承
interface Movable {
fun move() { println("移动中") }
}
interface Swimmable : Movable {
fun swim() { println("游泳中") }
}
class Fish : Swimmable {
// 只需实现未默认的方法
}
5. 函数式接口(SAM)
fun interface ClickListener {
fun onClick(view: String)
}
val listener = ClickListener { view ->
println("点击了 $view")
}
listener.onClick("button")
Kotlin 扩展
Kotlin 扩展
扩展函数/扩展属性允许在不修改原有类的情况下为其添加新功能,极大增强代码复用。
1. 扩展函数
// 为 String 添加扩展函数
fun String.reverse(): String = this.reversed()
// 为 List 添加扩展
fun <T> List<T>.secondOrNull(): T? = if (size > 1) this[1] else null
println("kotlin".reverse()) // niltoK
println(listOf(1,2,3).secondOrNull()) // 2
2. 扩展属性
val String.isEmail: Boolean
get() = this.contains("@") && this.contains(".")
println("test@example.com".isEmail) // true
3. 伴生对象扩展
class MyClass {
companion object { }
}
fun MyClass.Companion.create() = MyClass()
val m = MyClass.create()
4. 扩展与成员冲突
当成员函数与扩展函数同名时,成员函数优先:
class C {
fun foo() = "成员"
}
fun C.foo() = "扩展"
C().foo() // 输出 "成员"
5. 常用扩展库
apply/also/let/run/with:作用域函数,简化对象操作takeIf/takeUnless:条件返回to:创建 Pair
val user = User().apply {
name = "张三"
age = 20
}
Kotlin 数据类与密封类
Kotlin 数据类与密封类
1. 数据类(data class)
数据类自动生成 equals、hashCode、toString、copy 和 componentN 方法:
data class User(val id: Int, val name: String, val email: String = "")
val u1 = User(1, "张三")
val u2 = User(1, "张三")
println(u1 == u2) // true(结构相等)
println(u1.toString()) // User(id=1, name=张三, email=)
// copy 复制并修改
val u3 = u1.copy(name = "李四")
// 解构声明
val (id, name, email) = u1
println("$id $name $email")
2. 数据类要求
- 主构造函数至少有一个参数
- 所有主构造参数用 val/var 标记
- 不能是抽象、开放、密封或内部类
3. 密封类(sealed class)
密封类限制继承层级,所有子类必须在同一文件或包中,配合 when 实现穷尽分支:
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val code: Int, val msg: String) : Result()
object Loading : Result()
}
fun handle(r: Result) = when (r) {
is Result.Success -> "成功: ${r.data}"
is Result.Error -> "失败(${r.code}): ${r.msg}"
Result.Loading -> "加载中..."
}
4. 密封接口
sealed interface Shape {
data class Circle(val r: Double) : Shape
data class Rect(val w: Double, val h: Double) : Shape
}
Kotlin 泛型
Kotlin 泛型
1. 泛型函数
fun <T> identity(value: T): T = value
fun <T> List<T>.firstOr(default: T): T = if (isEmpty()) default else this[0]
println(identity("hello")) // hello
println(listOf(1,2).firstOr(0)) // 1
println(emptyList<Int>().firstOr(0)) // 0
2. 泛型类
class Box<T>(val content: T) {
fun get(): T = content
}
val intBox = Box(123)
val strBox = Box<String>("abc")
3. 类型上界
// T 必须是 Comparable 的子类型
fun <T : Comparable<T>> maxOf2(a: T, b: T): T =
if (a > b) a else b
println(maxOf2(10, 20)) // 20
println(maxOf2("a", "b")) // b
4. 型变:协变(out)与逆变(in)
// out:只能读取(生产者)
interface Source<out T> {
fun next(): T
}
// in:只能写入(消费者)
interface Sink<in T> {
fun accept(value: T)
}
5. 星投影
fun printList(list: List<*>) {
println(list.size)
}
printList(listOf(1, "a", true))
6. 泛型约束
fun <T> T.safeCastTo(clazz: Class<T>): T? = clazz.cast(this)
Kotlin 枚举类
Kotlin 枚举类
1. 基本枚举
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
val d = Direction.NORTH
println(d.name) // NORTH
println(d.ordinal) // 0
2. 带属性与构造参数
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
fun hex(): String = "#%06X".format(rgb)
}
println(Color.RED.hex()) // #FF0000
3. 枚举方法
// 遍历
for (c in Color.values()) {
println("${c.name}: ${c.hex()}")
}
// 按名称获取
val c = Color.valueOf("GREEN")
// 按位置获取
val second = Color.entries[1]
4. 枚举与 when 组合
enum class HttpStatus(val code: Int) {
OK(200), NOT_FOUND(404), ERROR(500)
}
fun describe(s: HttpStatus) = when (s) {
HttpStatus.OK -> "成功"
HttpStatus.NOT_FOUND -> "未找到"
HttpStatus.ERROR -> "服务器错误"
}
println(describe(HttpStatus.OK))
5. 枚举实现接口
interface Describable {
fun describe(): String
}
enum class Planet : Describable {
EARTH {
override fun describe() = "地球,人类家园"
},
MARS {
override fun describe() = "火星,红色星球"
}
}
Kotlin 对象表达式/声明
Kotlin 对象表达式/声明
1. 对象表达式(匿名对象)
用于创建临时对象,常用于实现接口或继承类:
val listener = object : ClickListener {
override fun onClick() {
println("按钮被点击")
}
}
// 匿名对象作为参数
fun setClick(handler: () -> Unit) { handler() }
setClick(object : () -> Unit {
override fun invoke() { println("执行") }
})
2. 对象声明(单例)
// object 关键字创建单例
object Config {
val appName = "MyApp"
var version = "1.0"
fun show() {
println("$appName v$version")
}
}
Config.show() // 全局唯一实例
Config.version = "1.1"
3. 伴生对象(companion object)
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
val TAG = "MyClass"
}
}
// 两种调用方式
val a = MyClass.create()
val b = MyClass.Factory.create()
println(MyClass.TAG)
4. 对象表达式 vs 声明区别
| 特性 | 对象表达式 | 对象声明 |
|---|---|---|
| 初始化时机 | 每次使用时 | 首次访问时(懒加载) |
| 用途 | 临时对象 | 单例 |
| 可赋值给变量 | 是 | 否(全局单例) |
5. 使用场景
- 比较器:
val cmp = object : Comparator<Int> {...} - 数据模型伴生工厂方法
- 全局配置、工具函数容器
kotlin 委托
Kotlin 委托
1. 类委托
通过 by 关键字将接口实现委托给另一个对象,实现组合复用:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { println("BaseImpl: $x") }
}
// 委托给 b,所有方法自动转发
class Derived(b: Base) : Base by b
val base = BaseImpl(10)
val d = Derived(base)
d.print() // BaseImpl: 10
2. 委托属性
// lazy 委托:第一次访问时初始化
val lazyValue: String by lazy {
println("计算中...")
"计算结果"
}
println(lazyValue) // 计算中... 计算结果
println(lazyValue) // 直接返回缓存值
// observable 委托:值变化时回调
var observed: String by Delegates.observable("初始") {
prop, old, new -> println("$old -> $new")
}
observed = "新值" // 初始 -> 新值
// vetoable 委托:可拦截赋值
var age: Int by Delegates.vetoable(18) {
_, _, new -> new in 0..150
}
3. 自定义委托
class LoggingDelegate<T>(private var value: T) {
operator fun getValue(thisRef: Any?, prop: kotlin.reflect.KProperty<*>): T {
println("读取 ${prop.name} = $value")
return value
}
operator fun setValue(thisRef: Any?, prop: kotlin.reflect.KProperty<*>, newValue: T) {
println("写入 ${prop.name} = $newValue")
value = newValue
}
}
var name by LoggingDelegate("默认")
name = "张三" // 写入 name = 张三
println(name) // 读取 name = 张三
4. 委托场景
- ViewModel 属性懒加载
- SharedPreferences 封装
- 属性变更监听与校验