整个的目录结构
首先需要添加jna.jar这个工具包。
一、编写java类,使用javac编译demo.java生成demo.class文件
Demo.java
package jni;
/**
* java与C之间的互相调用
* @author Lenovo
*
*/
public class Demo {
//将此类编译成头文件之后,在对应的头文件中生成需要在c中实现的函数
public native void callbackout() ;
public native int multi(int x);
public static void main(String args[]) {
System.load("C:\\Users\\Lenovo\\eclipse-workspace\\xx\\src\\jni\\libdemo.so");
int x=5;
Demo d=new Demo();
d.callbackout();
d.multi(x);
}
/**
* 下面的两个方法是C中将要调用的类
*/
public void out() {
System.out.println("This is the out function");
}
public int multis(int n) {
return n*n;
}
}
在导入load时,需要填写生成的so或者dll文件位置
二、使用javah jni.Demo 生成jni_Demo.h头文件
jni_Demo.h
#include "jni.h"
/* Header for class jni_Demo */
#ifndef _Included_jni_Demo
#define _Included_jni_Demo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jni_Demo
* Method: callbackout
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_jni_Demo_callbackout
(JNIEnv *, jobject);
/*
* Class: jni_Demo
* Method: multi
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_jni_Demo_multi
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
该头文件中的方法是java类中对应的native类型的方法,生成对应的接口,之后需在c文件中需要实现这些方法。
三、javap –s –p jni.Demo 获得java方法的签名
其中的签名可以根据对应的方法获取,签名分为两个部分,第一部分括号里的表示传递的参数类型,第二部分为返回的类型,如不带参的void方法对应的为()v ;再如int get(int x ,int y)该方法对应的为(II)I。
java类型及签名对应表
string对应的签名为Ljava/lang/String; 。
四、编写C文件,将jni_demo.h头文件、jni.h和jni_md.h放在一起
#include "jni.h"
#include "jni_Demo.h"
JNIEXPORT void JNICALL
Java_jni_Demo_callbackout(JNIEnv *env, jobject obj){
printf("Java_jni_Demo_callbackout\n");
jclass claz = (*env)->FindClass(env, "jni/Demo");
if (claz == 0) {
printf("class is error\n");
return ;
}
jmethodID methodid = (*env)->GetMethodID(env, claz, "out", "()V");
if(methodid==0){
printf("method is error \n");
return ;
}
(*env)->CallVoidMethod(env, obj, methodid);
}
JNIEXPORT jint JNICALL
Java_jni_Demo_multi(JNIEnv *env, jobject obj,jint x){
printf("Java_jni_Demo_multi\n");
jclass claz = (*env)->FindClass(env, "jni/Demo");
if (claz == 0) {
printf("class is error\n");
return 0;
}
jmethodID methodid = (*env)->GetMethodID(env, claz, "multis", "(I)I");
if(methodid==0){
printf("method is error \n");
return 0;
}
int result=(*env)->CallIntMethod(env, obj, methodid,x);
printf("multi()=%d",result);
return result;
}
对应的方法名为之前java生成头文件中的接口
调用分为三步:
第一步:通过findclass方法找到要调用方法的java类;
第二步:通过getmethod得到该方法的id;
第三步:call调用此方法。
五、编译成so或者dll文件
gcc –shared test.c –o libdemo.so
gcc -shared test.c -o test.dll
或者在makefile中编译
这样就得到java类中loadlibrary对应的文件
最后在java中运行main函数