原生方法是如何在ndk样本hellojni中注册的(它看起来不像静态寄存器或动态寄存器)



我对这个示例有点困惑,我知道本地方法有两种方式可以在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();

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

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函数篡改规则进行的。如果找不到这样的函数,就会抛出异常。如果包含jni.h和javah生成的头文件,一切都会解决。


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

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

最新更新