20220424 Java核心技术 卷2 高级特性 12
本地方法
原则上说,“ 100% 纯 Java ” 的解决方案是非常好的,但有时你也会想要编写或使用其他语言的代码(这种代码通常称为 本地代码 )
特别是在 Java 的早期阶段,许多人都认为使用 C++ 来加速 Java 应用中关键部分是个好主意。但是,实际上,这基本上是徒劳的。Java 平台实现比网络 I/O 要快得多,而网络 I/O 是真正的瓶颈
求助于本地代码是有缺陷的。如果应用的某个部分是用其他语言编写的, 那么就必须为需要支持的每个平台都提供一个单独的本地类库。用 C 或 C++ 编写的代码没有对通过使用无效指针所造成的内存覆写提供任何保护。编写本地代码很容易破坏你的程序,并感染操作系统
建议只有在必需的时候才使用本地代码。特别是在以下 3 种情况下,也许可以使用本地代码:
- 你的应用需要访问的系统特性和设备通过 Java 平台是无法实现的
- 你已经有了大量的测试过和调试过的用另一种语言编写的代码,并且知道如何将其导出到所有的目标平台上
- 通过基准测试,你发现所编写的 Java 代码比用其他语言编写的等价代码要慢得多
Java 平台有一个用于和本地 C 代码进行互操作的 API ,称为 Java 本地接口( JNI )
C++ 注意:你可以使用 C++ 代替 C 来编写本地方法。这样会有一些好处:类型检查会更严格一些,访问 JNI 函数会更便捷一些。然而,JNI 并不支持 Java 类和 C++ 类之间的任何映射机制
从 Java 程序申调用 C 函数
Java 编程语言使用关键字 native
表示本地方法
class HelloNative {
public static native void greeting();
}
本地方法既可以是静态的也可以是非静态的
为了实现本地代码,需要编写一个相应的 C 函数,你必须完全按照 Java 虚拟机预期的那样来命名这个函数。其规则是:
- 使用完整的 Java 方法名,比如:
HelloNative.greeting
。如果该类属于某个包,那么在前面添加包名,比如:v2ch12.helloNative.HelloNative.greeting
- 用下划线替换掉所有的句号,并加上
Java_
前缀,例如,Java_v2ch12_helloNative_HelloNative_greeting
- 如果类名含有非 ASCII 字母或数字,如:
_
,$
或是大于\u007F
的 Unicode 字符,用_0xxxx
来替代它们,xxxx
是该字符的 Unicode 值的 4 个十六进制数序列
PS D:\Develop\workspace\study\study-corejava\src\main\java> javac v2ch12/helloNative/HelloNative.java
PS D:\Develop\workspace\study\study-corejava\src\main\java> javah v2ch12.helloNative.HelloNative
生成文件 D:\Develop\workspace\study\study-corejava\src\main\java\v2ch12_helloNative_HelloNative.h
将函数原型从头文件中复制到源文件中,并且给出函数的实现代码:
#include "HelloNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_v2ch12_helloNative_HelloNative_greeting(JNIEnv* env, jclass cl)
{
printf("Hello Native World!\n");
}