初识 JNI

初识 JNI

JNI, Java Native Interface(Java本地接口).

概述

JNI 是用于和本地 C 代码进行交互操做的API。实际上能够经过许多语言编写,如C++、C#,本质上 Java 调用的是 dll/so 库 。此处说是和本地 C 代码互操做是由于 JNI API的支持。JNI API针对的是 C 语言,而不是Java。java

JNI 的出现的缘由有一些是为了弥补一些没法经过 Java 平台实现的功能。好比 Windows 的注册表,这是 Windows 独有的东西,Java 并无现成能够操做它的 API。后端

也有一些缘由是非 Java 语言编写的代码已经通过了大量的测试,无需从新用 Java 实现一套。bash

固然,最初也有 JVM 运行的比较慢的缘由,但随着 JVM 的不断发展,Java编写的代码有时已经不逊于一些 C/C++ 的代码了。函数

JNI 有着上述的一些好处,随着而来的是它会带来相应语言的缺点,
好比会引入 C 语言的无效指针形成的内存覆写问题等等。工具

因此说 JNI 实际上使用范围相对较窄,Web 后端方面用的比较少,安卓端用的相对更多一点。测试

示例 Hello World

如下为一个简单的示例编码

Java 部分

首先在在 Java 中声明 dll/so 库中定义的函数。
声明经过 native 关键字标识,提醒编译器该方法在外部定义。指针

// 为了简单,此处没有package
public class HelloNative {
  public static native void greeting();
}

C 部分

而后在 C 中定义函数,函数名有以下要求:code

  • Java_包名_类名_方法名 。(其中的.号都要改成 _下划线)
  • 若是类名中含有非 ASCII 码值,或说大于 \uoo7F 的 Unicode 字符,用 _0xxxx 来代替。
    xxxx 是该字符的Unicode值的4个十六进制数序列)
  • 方法重载须要在名称后加两个下划线,后再加上已编码的类型。

为了不在函数定义时候出错,Java 提供了 javah 工具完成函数名的编写操做。
javah 是经过类文件来生成相应的文件的,因此源代码必需要先编译才能够。接口

javah HelloNative

经过如上命令,会生成一个 HelloNative.h 的文件,这个文件包含了 greeting() 方法的声明。
复制该文件,改成 .c 文件,去掉一些不须要的东西,而后包含 #include "HelloNative.h" 便可。
而后将方法声明改成方法实现,在方法实现中编写具体的代码。

JNIEXPORT void JNICALL Java_HelloNative_greeting (JNIEnv* env, jclass cl) {
  printf("Hello Native World!");
}

以后就是编译代码了,此处仅粘贴我的测试过的命令,为 Windows 上的 MinGW64 上的 gcc 。

gcc -I "jdk/include" -I "jdk/include/win32" -D __int64="long long" -shared -o HelloNative.dll HelloNative.c

关于 -D __int64="long long" 参数的说明:

Windows 上的 jni_md.h 含有声明 typedef __int64 jlong; ,它专用于 cl 的。若是使用 gcc 须要设置 -D __int64="long long"
或者也能够修改此文件,如:

#ifdef __GNUC__
  typedef long long jlong;
#else
  typedef __int64 jlong;
#endif

调用

建立 HelloNativeTest 类以供测试:

public class HelloNativeTest {
    static {
        // 此处不须要 dll/so 后缀,系统会自动根据系统不一样换后缀
        System.loadLibrary("HelloNative");
    }

    public static void main(String[] args){
        HelloNative.greeting();
    }
}

记住这里打印的消息是经过 printf 打印的,不是 java 的代码打印的。

注:
一些本地代码的共享库必须先运行初始化代码,能够将初始化代码放置到JNI_OnLoad方法中,若是提供该方法,则虚拟机关
闭时会调用JNI_OnUnload方法,原型以下:

jint JNI_OnLoad(JavaVM* vm, void* reserved);    //返回它所需的虚拟机的最低版本,如JNI_VERSION_1_2
  void JNI_OnUnload(JavaVM* vm, void* reserved);
相关文章
相关标签/搜索