专注于快乐的事情

Java Native Interface

#什么是JNI?

JNI是Java Native Interface的英文缩写, 中文翻译为本地调用, 自从Java 1.1开始就成为了Java标准的一部分.

Java不是万能的,java是跨平台的语言,所付出的代价就是牺牲一些对底层的控制,而java要实现对底层的控制,就需要一些其他语言的帮助,这个就是native的作用。

Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。

Java Native适用的情况

  1. 为了使用底层的主机平台的某个特性,而这个特性不能通过JAVA API访问
  2. 为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的
  3. 为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。

Java调用C/C++的基本步骤

  1. 在Java中声明native()方法,然后编译;

  2. 用javah产生一个.h文件;

  3. 写一个.cpp(.c)文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中包含了JDK带的jni.h文件)

  4. 将第三步的.cpp文件编译成动态链接库文件;

  5. 在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。

下面将演示一个具体的例子

mac环境下用Java调用C的具体步骤

目标:调用c程序打印,“Hello,JNI”.

创建一个Java类,里面包含 native 方法和加载库loadLibrary方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Hello world!
*/
public class HelloNative {
static {
System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("HelloNative");
//System.load("/p/p-study/java-core/simple/src/main/java/HelloNative.so");
}

public static native void sayHello();

@SuppressWarnings("static-access")
public static void main(String[] args) {
new HelloNative().sayHello();
}
}

如果直接运行,会出现

Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path 虚拟机说不知道如何找到sayHello

生成.class文件,并使用javah命令,将.class文件生成.h文件

生成class文件
javac HelloNative.java

把java代码声明的JNI方法转化成C\C++头文件

javah HelloNative

会生成一个HelloNative.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */

#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloNative
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloNative_sayHello
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

用C语言实现这些本地方法

新建HelloNative.c,将上面步骤生成的.h文件包含在头文件中,并用C语言实现这些本地方法
代码如下

1
2
3
4
5
6
7
#include <jni.h>
#include "HelloNative.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *env,jclass obj){
printf("Hello,JNI");
}

编译刚才所写的C代码,生成.so文件

1
2
3
gcc -Wall -c HelloNative.c -I ./
-I /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/include
-I /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/include/darwin

生成动态连接库
gcc -shared HelloNative.o -o HelloNative.so

如果是linux,需要将darwin改为linux

运行

java HelloNative

如果出现“no HelloNative in java.library.path”的错误,修改java的代码,改为绝对路径

System.load(“/p/p-study/java-core/simple/src/main/java/HelloNative.so”);

终于出现了久违的“Hello,JNI“

参考

评论系统未开启,无法评论!