JNI简介
JNI 是 Java Native Interface 的缩写。 Java 本机接口(Java Native Interface,JNI)是一个标准的 Java API,它支持将 Java 代码与使用其他编程语言编写的代码相集成。如果您希望利用已有的代码资源,那么可以使用 JNI 作为您工具包中的关键组件。
下面介绍通过java程序调用C语言编写函数的库函数
宿主机:Ubuntu12.04
java_jdk:openjdk-1.7.0
c编译器:GCC_4.5
1.无参数无返回值的调用
JNI.java
public class JNI {
static {
//1.load加载C库
System.loadLibrary("native");//libnative.so
// }
public native static void hello("native");
public static void main(String[] args) {
//2.java.hello()-c.hello()
//C库函数与java函数的映射
//3.call,调用C库
JNI.hello();
}
}
编译 #javac JNI.java
生成头文件#javah -jni JNI
jv_v.c
#include<stdio.h>
#include<jni.h>
typedef struct {
char *name; /* Java里调用的函数名 */
char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
void *fnPtr; /* C语言实现的本地函数 */
} JNINativeMethod;
static const JNINativeMethod methods[] = {
{"hello", "()V", (void *)c_hello},//此处分别为java函数名,JNI字段描述符(可参考下方的表
//格),C中的函数指针
};
javac
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
{
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JNI");
if (cls == NULL)
{
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
void c_hello(JNIEnv *env,jobject cls)
{
printf("hello world\n");
}
#gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC -shared -o libnative.so jv_v.c
然后将生成的libnative.so库文件放到java文件目录下,使用java命令执行即可
JNI数据类型及JNI字段描述符
有参数有返回值(传入int变量,返回int变量)
JNI2.java
public class JNI2 {
static {
System.loadLibrary("native");
}
public native static int hello(int m);
public static void main(String[] args) {
System.out.print(JNI2.hello(120));
}
}
编译 #javac JNI2.java
生成头文件#javah -jni JNI2
jint_int.c
#include<stdio.h>
#include<jni.h>
#if 0
typedef struct{
char *name;//java
char *signature;//JNI
void *fnPtr;//
}JNINativeMethod;
#endif // 0
jint JNICALL Java_JNI3_hello
(JNIEnv *env, jclass cls, jint m);
static const JNINativeMethod methods[] = {
{"hello", "(I)I", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
{
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JNI2");
if (cls == NULL)
{
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
jint c_hello(JNIEnv *env,jobject cls,jint m)
{
printf("hello world,val = %d\n",m);
return 100;
}
#gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC -shared -o libnative.so jint_int.c
然后将生成的libnative.so库文件放到java文件目录下,使用java命令执行即可
传入字符串返回字符串
public class JNI3 {
static {
System.loadLibrary("native");
}
public native static String hello(String str);
public static void main(String[] args) {
System.out.print(JNI2.hello("chen"));
}
}
编译 #javac JNI3.java
生成头文件#javah -jni JNI3
js_s.c
#include<stdio.h>
#include<jni.h>
#if 0
typedef struct{
char *name;//java
char *signature;//JNI
void *fnPtr;//
}JNINativeMethod;
#endif //
jstring c_hello(JNIEnv *env, jclass cls, jstring str);
static const JNINativeMethod methods[] = {
{"hello", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_hello},//此处描述符的
//不同
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
{
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JNI2");
if (cls == NULL)
{
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
jstring c_hello(JNIEnv * env, jclass cls, jstring str)
{ /*此处需要字符串做转化处理,负责不能直接输出和返回
*/
const jbyte *cstr;
cstr = (*env)->GetStringUTFChars(env,str,NULL);//将字符串重新转化
if(cstr==NULL)
{
return NULL;
}
printf("hello world,c is %s\n",cstr);
(*env)->ReleaseStringUTFChars(env,str,cstr);//将字符串重新转化返回
return (*env)->NewStringUTF(env,"from c");
}
#gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC -shared -o libnative.so js_s.c
然后将生成的libnative.so库文件放到java文件目录下,使用java命令执行即可
传入数组返回int类型
JNI4.java
public class JNI4{
static {
System.loadLibrary("native");
}
public native static int hello(int[] a);
public static void main(String[] args) {
int[] a = {1,2,3};
System.out.print(JNI4.hello(a));
}
}
编译 #javac JNI4.java
生成头文件#javah -jni JNI4
ja_i.c
#include<stdio.h>
#include<jni.h>
#if 0
typedef struct{
char *name;//java
char *signature;//JNI
void *fnPtr;//
}JNINativeMethod;
#endif // 0
jint c_hello(JNIEnv *env, jclass cls, jintArray arr);
static const JNINativeMethod methods[] = {
{"hello", "([I)I", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
{
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JNI4");
if (cls == NULL)
{
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
jint c_hello(JNIEnv *env, jclass cls, jintArray arr)
{
jint *carr;
jint i,sum = 0;
carr = (*env)->GetIntArrayElements(env,arr,NULL);
if(carr==NULL)
return 0;
for(i=0;i<(*env)->GetArrayLength(env,arr);i++)
{
sum = sum+carr[i];
}
(*env)->ReleaseIntArrayElements(env,arr,carr,0);
return sum;
}
#gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC -shared -o libnative.so ja_i.c
然后将生成的libnative.so库文件放到java文件目录下,使用java命令执行即可
传入数组参数返回数组
public class JNI5 {
static {
System.loadLibrary("native");
}
public native static int[] hello(int[] a);
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = null;
b = JNI5.hello(a);
for(int i =0;i<b.length;i++)
System.out.print(b[i]);
}
}
编译 #javac JNI5.java
生成头文件#javah -jni JNI5
ja_a.c
#include<stdio.h>
#include<jni.h>
#include<stdlib.h>
#if 0
typedef struct{
char *name;//java
char *signature;//JNI
void *fnPtr;//
}JNINativeMethod;
#endif // 0
jintArray c_hello(JNIEnv *env, jclass cls, jintArray arr);
static const JNINativeMethod methods[] = {
{"hello", "([I)[I", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
{
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JNI5");
if (cls == NULL)
{
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
jintArray c_hello(JNIEnv *env, jclass cls, jintArray arr)
{
jint *carr;
jint *oarr;
jintArray rarr;
jint i,n = 0;
carr = (*env)->GetIntArrayElements(env,arr,NULL);//数组转化
if(carr==NULL)
return 0;//转化失败
n =(*env)->GetArrayLength(env,arr);//获取传入数组长度
oarr = malloc(sizeof(jint)*n);//分配内存空间
if(oarr==NULL)
{
(*env)->ReleaseIntArrayElements(env,arr,carr,0);//释放
return 0;
}
for(i=0;i<n;i++)
{
oarr [i] = carr[n-i-1];//逆序转化
}
(*env)->ReleaseIntArrayElements(env,arr,carr,0);
rarr = (*env)->NewIntArray(env,n);
if(rarr==NULL)
{
return 0;
}
(*env)->SetIntArrayRegion(env,rarr,0,n,oarr);
free(oarr);//释放内存空间
return rarr;
}
#gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC -shared -o libnative.soja_a.c
然后将生成的libnative.so库文件放到java文件目录下,使用java命令执行即可