step1:java访问c代码
废话不多说,举个最简单的例子
c++:
#include<jni.h>
extern "C" //声明导出下面的函数
JNIEXPORT void JNICALL Java_com_chc_VTcore_Inti(JNIEnv* env, jclass jc) {
int a = 0;
}
java:
package com.chc.VTcore;
public class Test{
public final static native void Inti();
}
好了,写完了。
然后回头看看c++代码的细节:
include jni :jni头文件,没啥说的。照着写就完事了
extern "C" :表示导出c风格函数,也是java调用函数的入口。照着写就完事了
JNIEXPORT void JNICALL :是jni.h提供的宏定义,语法 “JNIEXPORT 返回值类型 JNICALL” 用于导出函数;照着写就完事了(注意类型)
Java_com_chc_VTcore_Inti:函数名,这个非常关键!!,jni对方法名有严格的规定,“_”相当于“.”,即:Java.com.chc.VTcore.Inti 实际意义是:java的com.chc.VTcore包下的Inti 方法,所以在java里声明的是Inti();
(JNIEnv* env, jclass jc) 参数,这两个是固定的。env是指向 当!前!线!程!的java环境的指针,使用这个指针可以访问所有的java类,是c访问java入口。后面要用
举个带参数的例子:输入 int 返回 long
extern "C"
JNIEXPORT jlong JNICALL Java_com_chc_VTcore_Testfunc(JNIEnv* env, jclass jc,jint x) {
jlong a = x;
return a;
}
package com.chc.VTcore;
public class Test{
public final static native void Inti();
public final static native long Testfunc(int x);
}
类型如下:
Java类型 | JNI类型 | 描述 |
boolean | Jboolean | 无符号8位 |
byte | Jbyte | 无符号8位 |
char | Jchar | 无符号16位 |
short | Jshort | 有符号16位 |
int | Jint | 有符号32位 |
long | Jlong | 有符号64位 |
float | Jfloat | 有符号32位 |
double | Jdouble | 有符号64位 |
step2:c访问java代码
还是直接上代码,最简单的例子。
#include<jni.h>
static jenENV* jenv;
long UpdateCallback() {
jclass myClass = jenv->FindClass( "chc/VTcore/Callback");//找到类
jmethodID myMID= jenv->GetMethodID( myClass , "<init>", "()V");//找到构造函数
jobject myObj= jenv->NewObject(myClass , myMID);//使用构造函数new一个对象
jmethodID callBackMID = jenv->GetMethodID(myClass , "test", "(IJ)V");//找到一个带参方法
int a = 8;
long b = 9;
return jenv->CallVoidMethod( myObj, callBackMID,a,b);调用他
}
c访问java,就不需要遵循那些函数名要求了。
jenv里提供了全部的定义的访问、操作方法,上图说明:
你问我jenv的值是哪来的?初始化的时候我存了全局jenv指针
Java_com_chc_VTcore_Inti(JNIEnv* env, jclass jc) {
jenv = env;
}
FindClass:指定目录找到java类,返回类型 :jclass
参数:java类的路径。不要加 L ;
ps:可以find一下“java/lang/String”测试一下jni指针是否合适。切记不要写成 Ljava/lang/String;
GetObjectClass:传入java类的c内存数据,可以直接得到object 而不用查找java类。
jclass objclass = jenv2->GetObjectClass( (jobject)io_data);
GetMethodID :指定java类,按照名称和类型声明找到方法 返回值jmethodID
参数:目标class,函数名,函数参数and返回值 声明;
“<inti>” :是构造函数的意思,如果自己写了一个test方法,则为“test”
()V:看下表,()表示无参数,V表示返回void。如果输入(int int )返回 double ,则为(II)D。注意class类型的写法 L + 全路径类名 + ;
Java类型 | 类型标识 |
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | J |
float | F |
double | D |
String | L/java/lang/String; |
int[] | [I |
Object[] | [L/java/lang/Object; |
NewObject :new 一个java对象(object),传入class,构造函数id,自定义的数据,。。。,返回object
举例 :jobject jdata = jenv->NewObject(jCmdDataClass , jCmdDataMID , data, true);这个data和true就是构造函数需要的参数。
CallVoidMethod:执行返回值为void类型的函数,
参数(目标object,目标方法,n个参数....)
GetFieldID: 指定java类,按名称和类型找到成员的id。
参数:(目标class,目标数据成员名称,它的类型)
jfieldID jCmdDataObjectMID = jenv->GetFieldID( myclass, "javaCmdData", "Ljava/lang/Object;");
SetIntField:Set数据类型Field,传入object,传入成员id,后面是目标数据,即可设置成员的值
jenv2->SetIntField( jCmdData, jprotocolType, (jint)(((cgcom_codec_cmd_data_t *)data)->protocol_type));
//对于不确定成功的地方,判断一下是否捕获异常,如果有异常,不清理异常无法继续值执行,会中断。
jenv2->ExceptionCheck();
jenv2->ExceptionClear();
//释放资源
jenv2->DeleteLocalRef( jdata);
差不多了,剩下看官方文档吧,,,,