0Pricing
Kotlin Academy · 课时

实用反射

动态读取注解

实用反射 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

注解遇上反射

具有 RUNTIME 保留策略的注解可以在运行时通过反射发现。这种组合为序列化器、验证器和依赖注入提供了强大支持。

在本课中,我们将动态读取自己定义的注解。

读取类注解

每个 KClass 都提供一个 annotations 列表。我们可以扫描它,按类型查找特定注解。

@Retention(AnnotationRetention.RUNTIME)
annotation class Entity(val table: String)

@Entity("users")
class User

fun main() {
    val ann = User::class.annotations
        .filterIsInstance<Entity>()
        .first()
    println(ann.table)
}

findAnnotation 辅助工具

findAnnotation 扩展比手动筛选更加简洁。它会返回该注解,或者返回 null。

import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Entity(val table: String)

@Entity("orders")
class Order

fun main() {
    val ann = Order::class.findAnnotation<Entity>()
    println(ann?.table)
}

属性上的注解

属性也可以携带自己的注解。遍历 memberProperties,检查每个属性的 annotations。

import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Column(val name: String)

class Product(@Column("product_id") val id: Int, val title: String)

fun main() {
    Product::class.memberProperties.forEach { prop ->
        val col = prop.findAnnotation<Column>()
        if (col != null) println(prop.name + " -> " + col.name)
    }
}

构建一个小型序列化器

将属性读取与注解结合起来即可生成输出。这里我们将每个属性映射为一个 key=value 字符串;如果存在列名,就使用列名。

import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Column(val name: String)

class Item(@Column("item_id") val id: Int, val name: String)

fun main() {
    val item = Item(7, "Book")
    val parts = Item::class.memberProperties.map { p ->
        val key = p.findAnnotation<Column>()?.name ?: p.name
        key + "=" + p.getter.call(item)
    }
    println(parts.joinToString(", "))
}

使用标记跳过内容

标记注解可以标记需要忽略的属性。我们使用 hasAnnotation 检查它是否存在。

import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.hasAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Transient2

class Account(val id: Int, @Transient2 val secret: String)

fun main() {
    Account::class.memberProperties
        .filterNot { it.hasAnnotation<Transient2>() }
        .forEach { println(it.name) }
}

读取注解参数

获取注解实例后,它的参数就是普通属性。像读取任何字段一样读取它们即可。

import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Validated(val min: Int, val max: Int)

@Validated(min = 1, max = 100)
class Quantity

fun main() {
    val v = Quantity::class.findAnnotation<Validated>()!!
    println("range " + v.min + ".." + v.max)
}

函数上的注解

函数也可以添加注解并进行检查。框架会利用这一点查找处理器,例如测试运行器会定位测试方法。

import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Route(val path: String)

class Api {
    @Route("/home")
    fun home() = "home page"
}

fun main() {
    Api::class.memberFunctions.forEach { f ->
        f.findAnnotation<Route>()?.let { println(f.name + " @ " + it.path) }
    }
}

驱动行为

读取路由注解,并实际分派一次调用。这正是路由框架工作方式的核心。

import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.findAnnotation

@Retention(AnnotationRetention.RUNTIME)
annotation class Route(val path: String)

class Api {
    @Route("/ping")
    fun ping() = "pong"
}

fun main() {
    val api = Api()
    val target = "/ping"
    Api::class.memberFunctions.forEach { f ->
        if (f.findAnnotation<Route>()?.path == target) {
            println(f.call(api))
        }
    }
}

实际应用

注解驱动的反射支撑着许多库:

  • JSON 序列化:将字段映射到键
  • 验证:强制执行约束
  • 路由:将路径匹配到处理器
  • 依赖注入:连接组件

保持针对性

反射最好限制在设置阶段,以及只运行一次或很少运行的框架代码中。可以缓存结果时,请尽量缓存。对于每次请求都会经过的高频路径,优先使用编译时处理。

快速检查

测试您对实际反射应用的理解。

回顾

您结合注解和反射实现了以下功能:

  • 查找类、属性和函数上的注解
  • 在运行时读取注解参数
  • 构建小型序列化器和路由分派器
  • 使用标记注解跳过字段

实际框架就是这样构建的。

常见问题解答

「实用反射」课时是免费的吗?

是的 — 「实用反射」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「实用反射」这节课中我会学到什么?

动态读取注解 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「实用反射」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用注解
  2. 定义注解
  3. 反射基础
  4. 实用反射
← 返回 Kotlin Academy