ILE 本机方法中的字符串

许多 Java™ 本机接口 (JNI) 函数接受 C 语言样式的字符串作为参数。 例如, FindClass() JNI 函数接受用于指定类文件的标准名称的字符串参数。 如果找到类文件,那么它将由 FindClass()装入,并将对它的引用返回给 FindClass()的调用者。

所有 JNI 函数都期望其字符串参数以 UTF-8编码。 有关 UTF-8的详细信息,您可以引用 JNI 规范,但在大多数情况下,观察到 7 位美国信息交换标准代码 (ASCII) 字符等同于其 UTF-8 表示。 7 位 ASCII 字符实际上是 8 位字符,但它们的第一个位始终是 0。 因此,大多数 ASCII C 字符串实际上已采用 UTF-8。

缺省情况下,服务器上的集成语言环境 (ILE) C 编译器在扩展二进制编码的十进制交换代码 (EBCDIC) 中运行,因此传递到 JNI 函数的字符串需要转换为 UTF-8。 可通过两种方式运行它。 可以使用文字串,也可以使用动态字符串。 文字字符串 是在编译源代码时已知其值的字符串。 动态字符串 是其值在编译时未知,但实际在运行时计算的字符串。

文字字符串

如果该字符串可以用 ASCII 表示 (大多数是 ASCII) ,那么该字符串可以由更改编译器当前代码页的 pragma 语句括起来。 然后,编译器以 JNI 所需的 UTF-8 格式在内部存储该字符串。 如果该字符串不能以 ASCII 表示,那么更容易将原始扩展二进制编码的十进制交换代码 (EBCDIC) 字符串视为动态字符串,并在将其传递到 JNI 之前使用 iconv() 对其进行处理。

例如,要查找名为 java/lang/String的类,代码如下所示:

    #pragma convert(819)
    myClass = (*env)->FindClass(env,"java/lang/String");
    #pragma convert(0)

第一个编译指示 (编号为 819) 通知编译器以 ASCII 格式存储所有后续的双引号字符串 (文字串)。 第二个编译指示 (编号为 0) 指示编译器还原为双引号字符串的编译器的缺省代码页,通常是 EBCDIC 代码页 37。 因此,通过将此调用与这些编译指示括起来,我们满足 JNI 要求,即字符串参数以 UTF-8编码。

注意: 请注意文本替换。 例如,如果您的代码如下所示:

    #pragma convert(819)
    #define MyString "java/lang/String"
    #pragma convert(0)
    myClass = (*env)->FindClass(env,MyString);

然后,生成的字符串为 EBCDIC ,因为 MyString 的值在编译期间会被替换到 FindClass() 调用中。 在这种替代的时候,编号为 819 的 pragma 是没有效力的。 因此,文字字符串不会存储在 ASCII 中。

将动态字符串转换为 EBCDIC , Unicode 和 UTF-8

要处理在运行时计算的字符串变量,可能需要在 EBCDIC , Unicode 和 UTF-8之间转换字符串。 可以使用 iconv() API 完成转换。 在 将 Java 本机接口用于本机方法示例的示例 3中,例程创建,使用并销毁 iconv() 转换描述符。 此方案避免了多线程使用 iconv_t 描述符的问题,但对于性能敏感代码,最好在静态存储器中创建转换描述符,并使用互斥 (mutex) 或其他同步设施对其进行多次访问。