0

我对这个示例有点困惑,我知道本机方法有两种在 JNI 中注册的方式。如果您使用静态签名,则需要生成签名,例如* .h,并将其包含在您的本机文件中。显然,hello-jni 不使用动态的。代码如下所示:

#include <string.h>
#include <jni.h> 

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

和java

public native String  stringFromJNI();

我在谷歌上搜索过,发现了一些关于 JVM 的线索,我对 JVM 知之甚少,有人能帮忙吗?

4

1 回答 1

0

C 代码使用的函数声明可以通过以下方式生成:

javah -classpath apps/samples/hello-jni/project/src com.example.hellojni.HelloJni 

javah处理从 HelloJni.java 编译的字节码文件 (HelloJni.class) 以将声明的方法提取native到 C 函数原型中。该实现正在定义其中之一:

jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*, jobject);

它可能是这样做的,而无需先声明函数,也无需使用javah. 在 C 中,这通常是允许的。也许他们复制、粘贴和编辑了 的输出javah,尽管你可以学会做你脑子里想的事情javah

更新: 此外,在 C 中,函数声明不需要命名参数。在实现中,您必须为使用的每个参数命名。因此,以下是可能的:

Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
    // implementation
}

或者,由于实现不使用第二个参数:

Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject )
{
    // implementation
}

链接

动态链接发生在一些 Java 代码调用时system.loadLibrary("name")。这种调用的典型位置是在每个类的静态初始化块中,该块声明native由库实现的方法:

public class HelloJni
{
   static { system.loadLibrary("hellojni"); }
   ...
}

然后,JVM 在属性中的搜索路径上搜索共享库(.so 或 .dll)java.library.path。它尝试各种依赖于平台的前缀(“lib”)和后缀(“.so”、“.dll”)来查找文件。如果找不到任何此类文件,则会引发异常。

独立地,当调用用 声明的函数时native,JVM 会在加载的库中搜索与函数名称匹配的导出函数。匹配是根据 C 编译器/链接器使用的 JNI 函数命名约定javah和 C 函数修饰规则完成的。如果找不到这样的函数,则抛出异常。如果包含 jni.h 和由javah.


注意:要非常小心NewStringUTF。它需要一个以 0 结尾的 Unicode 字符串,并带有修改后的 UTF-8 编码。该示例依赖于字符串中使用的有限字符子集、源文件编码以及编译器从刚刚发生的文字构造 char 数组以创建与字符串的修改后的 UTF-8 编码相同的字节序列。

如果您可以使用 C++11 而不是 C,则NewString可以很好地使用std::u16stringUTF-16 代码单元。(UTF-16 代码单元是 Java 内部使用的。)

于 2013-06-26T17:39:56.380 回答