JNI
什么是JNI?
Java Native Interface
Java本地接口
JNI能做什么?
开发JNI程序会受到系统环境的限制,因为用C/C++语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,而且各个平台对标准C/C++的规范和标准库函数实现方式也有所区别。这就造成使用了JNI接口的JAVA程序,不再像以前那样自由的跨平台。如果要实现跨平台,就必须将本地代码在不同的操作系统平台下编译出相应的动态库。
Demo流程(OS X下)
一 编写声明了native关键字的java类,保存于HelloWorld.java
- 在本地创建一个文件夹jnitest
- jnitest文件夹下创建HelloWorld.java;
- HelloWorld.java代码如下:
package com.study.jnilearn;
public class HelloWorld{
public static native String sayHello(String name);
public static void main(String[] args){
System.loadLibrary("HelloWorld");
String text = sayHello("HelloWorld!");
System.out.println(text);
}
}
二 使用javac将HelloWorld.java源代码编译成HelloWorld.class字节码文件
1.在jnitest下创建一个bin文件夹
2.使用 javac 将 HelloWorld.java 源代码编译成 HelloWorld.class 字节码文件
javac HelloWorld.java -d bin
3.这样会在bin文件夹下生成对于的class文件,其路径为bin/com/study/jnilearn/HelloWorld.class
三 将使用javah生成对应的头文件HelloWorld.h
javah -jni -classpath bin -o HelloWorld.h com.study.jnilearn.HelloWorld
这会在jnitest文件夹下生成HelloWorld.h文件
四 创建HelloWorld.c文件,并实现里面的native方法
在HelloWorld.h的同级目录下新建一个HelloWorld.c文件,实现native声明的方法
#include "HelloWorld.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_study_jnilearn_HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello
(JNIEnv *env, jclass cls, jstring j_str){
const char *c_str = NULL;
char buff[128] = {0};
c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
if (c_str == NULL){
printf("out of memory.\n");
return NULL;
}
(*env)->ReleaseStringUTFChars(env, j_str, c_str);
printf("C Str:%s\n", c_str);
sprintf(buff, "%s", c_str);
return (*env)->NewStringUTF(env, buff);
}
#ifdef __cplusplus
}
#endif
五 编译C代码,生成本地库
gcc -dynamiclib -o libHelloWorld.jnilib HelloWorld.c -framework JavaVM -I$JAVA_HOME/include -I/$JAVA_HOME/include/darwin
这样会在jnitest文件夹下生成libHelloWorld.jnilib
六 运行java程序
java -classpath bin com.study.jnilearn.HelloWorld
输出:
C Str:HelloWorld!
HelloWorld!
c++代码生成动态库的不同之处
1.新建cpp文件,对于JNIEnv *env的调用是不同的
#include "HelloWorld.h"
extern "C" {
/*
* Class: com_study_jnilearn_HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello
(JNIEnv *env, jclass cls, jstring j_str){
const char *c_str = NULL;
char buff[128] = {0};
c_str = env->GetStringUTFChars( j_str, NULL);
if (c_str == NULL){
printf("out of memory.\n");
return NULL;
}
env->ReleaseStringUTFChars(j_str, c_str);
printf("C Str:%s\n", c_str);
sprintf(buff, "%s", c_str);
return env->NewStringUTF(buff);
}
}
2.生成动态库的源文件是不同的
gcc -dynamiclib -o libHelloWorld.jnilib HelloWorld.cpp -framework JavaVM -I$JAVA_HOME/include -I/$JAVA_HOME/include/darwin