java高级编程,JNI的使用。java代码调用c程序,jni.java
java高级编程,JNI的使用。java代码调用c程序,jni.java
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$
相关文章
- 暂无相关文章
用户点评