Kotlin external 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的 external 关键字实现了与原生代码的互操作性。 它标记了在 Kotlin 之外实现的声明。 本教程通过实际例子深入探讨了 external 关键字。
基本定义
Kotlin 中的 external 关键字表示声明是在特定于平台的代码中实现的。 它用于 JNI (Java Native Interface) 和 JavaScript 互操作性。 实际的实现必须在外部提供。
基本 external 函数
external 最简单的用法是声明一个在原生代码中实现的函数。 函数体被省略,因为它是在外部提供的。
package com.zetcode
external fun helloFromNative()
fun main() {
helloFromNative()
}
在这里,我们声明一个没有实现的 external 函数。 实际的原生代码将用 C/C++ 编写,并通过 JNI 链接。 Kotlin 代码可以像调用任何其他函数一样调用它。
使用 JNI 的 external
在使用 JNI 时,external 标记在 C/C++ 中实现的函数。 函数名称必须遵循 JNI 命名约定才能正确链接。
package com.zetcode
external fun nativeAdd(a: Int, b: Int): Int
fun main() {
System.loadLibrary("nativeLib")
val sum = nativeAdd(5, 7)
println("Sum from native: $sum")
}
此示例显示了一个将两个整数相加的原生函数。 对应的 C 函数将被命名为 Java_com_zetcode_JNIFunction_nativeAdd。 在调用原生函数之前,会加载库。
external 属性
属性也可以标记为 external。 getter 和 setter 必须在原生代码中实现。 这对于访问原生状态很有用。
package com.zetcode
external var nativeCounter: Int
fun main() {
System.loadLibrary("nativeLib")
nativeCounter = 10
println("Counter value: $nativeCounter")
}
在这里,我们声明一个由原生代码支持的 external 属性。 原生实现必须同时提供 getter 和 setter 函数。 该属性的行为类似于常规的 Kotlin 属性。
external 类
整个类可以标记为 external。 这种类的所有成员也必须是 external。 这对于 JNI 包装器很常见。
package com.zetcode
external class NativeMath {
fun add(a: Int, b: Int): Int
fun subtract(a: Int, b: Int): Int
}
fun main() {
System.loadLibrary("nativeLib")
val math = NativeMath()
println("5 + 3 = ${math.add(5, 3)}")
println("5 - 3 = ${math.subtract(5, 3)}")
}
这个 external 类声明了在原生代码中实现的方法。 原生实现必须提供所有声明的方法。 该类可以像任何常规的 Kotlin 类一样使用。
JavaScript 互操作
当目标是 JavaScript 时,external 用于从 Kotlin 代码访问 JavaScript API。 声明直接映射到 JavaScript 对象。
package com.zetcode
external fun alert(message: String)
external val document: dynamic
fun main() {
alert("Hello from Kotlin/JS!")
document.getElementById("demo").innerHTML = "Updated"
}
在 Kotlin/JS 中,external 声明映射到 JavaScript API。 这里我们声明了 alert 函数和 document 对象。 dynamic 类型允许灵活访问 JavaScript 属性。
external 伴生对象
伴生对象可以标记为 external,以便为静态方法提供原生实现。 这对于实用程序函数很有用。
package com.zetcode
class NativeUtils {
companion object {
external fun getSystemTime(): Long
}
}
fun main() {
System.loadLibrary("nativeLib")
val time = NativeUtils.getSystemTime()
println("System time: $time")
}
此示例显示了一个 external 伴生对象函数。 原生实现将是一个静态 JNI 函数。 该函数通过伴生对象像静态方法一样被调用。
使用平台库的 external
external 关键字可以与特定于平台的库一起使用。 此示例演示了访问 Windows API 函数。
package com.zetcode
external fun MessageBoxA(
hWnd: Int,
text: String,
caption: String,
uType: Int
): Int
fun main() {
System.loadLibrary("user32")
MessageBoxA(0, "Hello from Kotlin", "Message", 0)
}
在这里,我们将 Windows MessageBoxA API 声明为 external。 该函数从 user32.dll 加载。 这演示了 Kotlin 中的特定于平台的互操作性。
external 的最佳实践
- 谨慎使用: 仅在互操作性必要时使用
external。 - 彻底记录: 清楚地记录原生要求和调用约定。
- 处理错误: 为原生调用实现正确的错误处理。
- 考虑替代方案: 在使用原生代码之前评估 Kotlin 多平台库。
- 彻底测试: 原生代码可能导致崩溃 - 进行广泛的测试。
来源
本教程深入探讨了 Kotlin 的 external 关键字,展示了它在 JNI、JavaScript 和平台互操作性中的应用。 我们探讨了各种场景,包括函数、属性、类和伴生对象。 正确使用 external 可以实现强大的原生集成。
作者
列出 所有 Kotlin 教程。