如何在ndk示例中注册本机方法hello-jni(它看起来不像静态寄存器或动态寄存器)

时间:2013-06-26 15:05:33

标签: java-native-interface

我对此示例感到困惑,我知道本机方法有两种方法可以在JNI中注册。如果您使用静态签名,则需要生成签名,例如 * .h,并将其包含在您的本机文件中。显然,你好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();

我在google搜索过,发现了一些关于JVM的提示,我对JVM知之甚少,有人可以帮忙吗?

1 个答案:

答案 0 :(得分: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在属性java.library.path中的搜索路径上搜索共享库(.so或.dll)。它尝试各种与平台相关的前缀(“lib”)和后缀(“。so”,“。dll”)来查找文件。如果找不到任何此类文件,则会抛出异常。

独立地,当对使用native声明的函数进行调用时,JVM会在加载的库中搜索与函数名称匹配的导出函数。匹配是根据javah使用的JNI函数命名约定和C编译器/链接器使用的C函数修改规则完成的。如果找不到这样的函数,则抛出异常。如果您包含由javah生成的jni.h和标头,则应该可以解决所有问题。


注意:对NewStringUTF要非常小心。它采用带有修改的UTF-8编码的0终止的Unicode字符串。该示例依赖于字符串中使用的有限字符子集,源文件编码和编译器从字面值开始的char数组的构造,以创建与字符串的修改的UTF-8编码相同的字节序列。

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