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);

 

差不多了,剩下看官方文档吧,,,,