java高级编程,JNI的使用。java代码调用c程序

Java Native Interface (JNI)标准是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。

此外,在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。

那么如何来通过java代码来调用C程序呢?

1 既然我们要调用C语言程序,那么就需要加载c库

2 如何使用java来调用C语言程序呢,这就需要java和C语言建立映射。

3 然后调用

/* 1. load */

/* 2. map Java hello <-->c c_hello */

/* 3. call */

使用的编程工具是source insight编写代码,VmWare虚拟机 运行ubuntu12.04来编译,运行程序。虚拟机中需要安装java开发环境。


首先,先完成代码。

java代码

在静态代码块中加载c库

public class JNIDemo {
static { /* 1. load */
System.loadLibrary("native"); /* libnative.so */
  }
public native void hello();
public static void main (String args[]) {
JNIDemo d = new JNIDemo();
/* 2. map java hello <-->c c_hello */
/* 3. call */
d.hello();
}
}

主要是第二部  建立映射

这一部分,我们需要阅读JNI的文档。

JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
cached_jvm = jvm; /* cache the JavaVM pointer */
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "C");
if (cls == NULL) {
return JNI_ERR;
}
/* Use weak global ref to allow C class to be unloaded */
Class_C = (*env)->NewWeakGlobalRef(env, cls);
if (Class_C == NULL) {
return JNI_ERR;
}
/* Compute and cache the method ID */
MID_C_g = (*env)->GetMethodID(env, cls, "g", "()V");
if (MID_C_g == NULL) {
return JNI_ERR;
}
return JNI_VERSION_1_2;
}

这段例子 ,等下需要使用

JNINativeMethod nm;
nm.name = "g";
/* method descriptor assigned to signature field */
nm.signature = "()V";
nm.fnPtr = g_impl;
(*env)->RegisterNatives(env, cls, &nm, 1);

这段话,也需要使用

然后,编写native.c文件

    ---- JNI_OnLoad()与JNI_OnUnload()函数的用途

 当Android的VM(Virtual Machine)执行到System.loadLibrary()函数时,首先会去执行C组件里的JNI_OnLoad()函数。它的用途有二:

(1)告诉VM此C组件使用那一个JNI版本。如果你的*.so档没有提供JNI_OnLoad()函数,VM会默认该*.so档是使用最老的JNI 1.1版本。由于新版的JNI做了许多扩充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM。

(2)由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_OnLoad(),所以C组件的开发者可以藉由JNI_OnLoad()来进行C组件内的初期值之设定(Initialization) 。


需要完成JNI_OnLoad方法。建立连接
#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ 虚拟机中的路径 */
#include <stdio.h>

/* 结构体 */
#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif
void c_hello(JNIEnv *env, jobject cls)
{
printf("Hello, world!\n");
}
static const JNINativeMethod methods[] = {
{"hello", "()V", (void *)c_hello},
};
/* System.loadLibrary */
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, "JNIDemo");
if (cls == NULL) {
return JNI_ERR;
}
/* 2. map java hello <-->c c_hello */
if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
return JNI_ERR;
return JNI_VERSION_1_4;
}

完成代码编写之后,将代码上传到linux虚拟机上,然后编译。

进入当前的目录

book@book-virtual-machine:~$ cd /work/javaproject/18th_jni/

编译java文件

book@book-virtual-machine:/work/javaproject/18th_jni$ javac JNIDemo.java 

编译C语言程序 的得到 libnative.so 库文件

book@book-virtual-machine:/work/javaproject/18th_jni$ gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC  -shared  -o libnative.so native.c

指定库的路径(在linux下的编程,毫无疑问的迟早都要用到LD_LIBRARY_PATH这个环境变量)

book@book-virtual-machine:/work/javaproject/18th_jni$ export LD_LIBRARY_PATH=.(.表示当前路径)

运行java程序

book@book-virtual-machine:/work/javaproject/18th_jni$ java JNIDemo 

打印出来我们在C语言程序中输出的信息

Hello, world!

在这个例子里 是没有参数和返回值的。

二 、含有参数和返回的情况下如何来编写程序

java代码

public class JNIDemo {
static { /* 1. load */
System.loadLibrary("native"); /* libnative.so */
  }
public native int hello(int m);
public static void main (String args[]) {
JNIDemo d = new JNIDemo();
/* 2. map java hello <-->c c_hello */
/* 3. call */
System.out.println(d.hello(123));
}
}

那么C语言程序编写:



#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>


#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif


jint c_hello(JNIEnv *env, jobject cls, jint m)
{
printf("Hello, world! val = %d\n", m);
return 100;
}
static const JNINativeMethod methods[] = {
{"hello", "(I)I", (void *)c_hello},
};
/* System.loadLibrary */
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, "JNIDemo");
if (cls == NULL) {
return JNI_ERR;
}
/* 2. map java hello <-->c c_hello */
if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
在这个程序中,修改了一下程序中的c_hello方法

jint c_hello(JNIEnv *env, jobject cls, jint m)
{
printf("Hello, world! val = %d\n", m);
return 100;
}
static const JNINativeMethod methods[] = {
{"hello", "(I)I", (void *)c_hello},
};结构体变量的初始化的参数类型也做了修改 参数类型 参考JNI手册

编译运行方法同上。

book@book-virtual-machine:/work/javaproject/18th_jni/02$ ls
JNIDemo.java  native.c  readme.txt
book@book-virtual-machine:/work/javaproject/18th_jni/02$ javac JNIDemo.java 
book@book-virtual-machine:/work/javaproject/18th_jni/02$ gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC  -shared  -o libnative.so native.c 
book@book-virtual-machine:/work/javaproject/18th_jni/02$ export LD_LIBRARY_PATH=.
book@book-virtual-machine:/work/javaproject/18th_jni/02$ java JNIDemo 
Hello, world! val = 123
100

三 、在第二个程序中,传入的参数是int型,传入String如何操作

java代码

public class JNIDemo {
static { /* 1. load */
System.loadLibrary("native"); /* libnative.so */
  }
public native String hello(String str);
public static void main (String args[]) {
JNIDemo d = new JNIDemo();
/* 2. map java hello <-->c c_hello */
/* 3. call */
System.out.println(d.hello("this is java"));
}
}

编写native.c文件:

#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif
jstring JNICALL c_hello(JNIEnv *env, jobject cls, jstring str)
{
//printf("this is c : %s\n", str);
//return "return from C";
const jbyte *cstr;
cstr = (*env)->GetStringUTFChars(env, str, NULL);
if (cstr == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("Get string from java :%s\n", cstr);
(*env)->ReleaseStringUTFChars(env, str, cstr);
return (*env)->NewStringUTF(env, "return from c");
}
static const JNINativeMethod methods[] = {
{"hello", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_hello},
};
/* System.loadLibrary */
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, "JNIDemo");
if (cls == NULL) {
return JNI_ERR;
}
/* 2. map java hello <-->c c_hello */
if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
return JNI_ERR;
return JNI_VERSION_1_4;
}

编译运行的方法同上

book@book-virtual-machine:/work/javaproject/18th_jni/02$ cd ../
book@book-virtual-machine:/work/javaproject/18th_jni$ cd 03/
book@book-virtual-machine:/work/javaproject/18th_jni/03$ javac JNIDemo.java 
book@book-virtual-machine:/work/javaproject/18th_jni/03$ gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC  -shared  -o libnative.so native.c 
book@book-virtual-machine:/work/javaproject/18th_jni/03$ export LD_LIBRARY_PATH=.
book@book-virtual-machine:/work/javaproject/18th_jni/03$ java JNIDemo 
Get string from java :this is java
return from c
book@book-virtual-machine:/work/javaproject/18th_jni/03$ 


四 、当传入数组类型的参数

java代码

public class JNIDemo {
static { /* 1. load */
System.loadLibrary("native"); /* libnative.so */
  }
public native int hello(int[] a);
public static void main (String args[]) {
JNIDemo d = new JNIDemo();
int [] a = {1, 2, 3}; 
/* 2. map java hello <-->c c_hello */
/* 3. call */
System.out.println(d.hello(a));
}
}

2 native.c程序编写:

#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif
jint c_hello(JNIEnv *env, jobject cls, jintArray arr)
{
jint *carr;
jint i, sum = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
for (i=0; i< (*env)->GetArrayLength(env, arr); i++) {
sum += carr[i];
}
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return sum;
}
satic const JNINativeMethod methods[] = {
{"hello", "([I)I", (void *)c_hello},
};
/* System.loadLibrary */
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, "JNIDemo");
if (cls == NULL) {
return JNI_ERR;
}

/* 2. map java hello <-->c c_hello */
if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
return JNI_ERR;
return JNI_VERSION_1_4;
}
编译运行结果

book@book-virtual-machine:/work/javaproject/18th_jni/04$ javac JNIDemo.java 
book@book-virtual-machine:/work/javaproject/18th_jni/04$ gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -fPIC  -shared  -o libnative.so native.c 
book@book-virtual-machine:/work/javaproject/18th_jni/04$ export LD_LIBRARY_PATH=.
book@book-virtual-machine:/work/javaproject/18th_jni/04$ java JNIDemo 
6
book@book-virtual-machine:/work/javaproject/18th_jni/04$ 



五 、传入 数组 返回数组

java代码的编写:

public class JNIDemo {
static { /* 1. load */
System.loadLibrary("native"); /* libnative.so */
  }
public native int[] hello(int[] a);
public static void main (String args[]) {
JNIDemo d = new JNIDemo();
int [] a = {1, 2, 3}; 
int [] b = null;
int i;
/* 2. map java hello <-->c c_hello */
/* 3. call */
b = d.hello(a);
for (i = 0; i < b.length; i++)
System.out.println(b[i]);
}
}


native.c程序的编写



#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#include <stdlib.h>
 
#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif


jintArray c_hello(JNIEnv *env, jobject cls, jintArray arr)
{
jint *carr;
jint *oarr;
jintArray rarr;

jint i, n = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}


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-1-i];
}
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
/* create jintArray */
rarr = (*env)->NewIntArray(env, n);
if (rarr == NULL)
{
return 0;
}


(*env)->SetIntArrayRegion(env, rarr, 0, n, oarr);
free(oarr);

return rarr;
}
static const JNINativeMethod methods[] = {
{"hello", "([I)[I", (void *)c_hello},
};
/* System.loadLibrary */
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, "JNIDemo");
if (cls == NULL) {
return JNI_ERR;
}


/* 2. map java hello <-->c c_hello */
if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
return JNI_ERR;


return JNI_VERSION_1_4;
}

运行结果

book@book-virtual-machine:/work/javaproject/18th_jni/04$ cd ../
book@book-virtual-machine:/work/javaproject/18th_jni$ cd 05/
book@book-virtual-machine:/work/javaproject/18th_jni/05$ javac JNIDemo.java 
^[[Abook@book-virtual-machine:/work/javaproject/18th_jni/05$ gcc -I/usr/lib/jvm/java-1.7.0-opk-amd64/include/ -fPIC  -shared  -o libnative.so native.c 
book@book-virtual-machine:/work/javaproject/18th_jni/05$ export LD_LIBRARY_PATH=.
book@book-virtual-machine:/work/javaproject/18th_jni/05$ java JNIDemo 
3
2
1
book@book-virtual-machine:/work/javaproject/18th_jni/05$ 













  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值