java jni 指针_JNI知识(七)C++/C接口是指针的情况

有时候我们的C++/C带代码是现成的,需要向上用JNI封装,然后用Java调用。Java中是没有指针的,但是Java通过JNI调用C++/C接口,C++/C是有指针的,这种情况Java该作何处理。C++/C指针作为输出参数

这种在前面出参为String类型的情况最后更为一般的情况已经提到过。这里在展开来讨论。基本类型

example:

Java接口:

public void getAge(int age[]);

JNI:

JNIEXPORT void JNICALL Java_setAge_ 1native (JNIEnv *env, jclass thiz,

jintArray age)

{

int age;

getAge(&age); // setAge为更下层的函数接口

jint  as32AgeArray[1];

s32AgeArray [0] = age;

/* 这个操作实际有些像memcpy,如果数组大小比较大,并且拷贝若干

个连续的元素,就修改上面方法的第2,3个参数即可

*/

env->SetIntArrayRegion(age, 0, 1, (jint *) as32AgeArray);

}输出参数类型是class

/* C++/C中 struct */

typedef struct _Para_tag

{

int x;

short y;

char az[100];

char h;

unsigned int t;

}Para_Tag;

对应的Java中的class为:

public class Para_Tag

{

int m_x;

short m_y;

String m_z;

char m_h;

long m_t;

public Para_tag(int x,short y,String z,char h,long t)

{

m_x = x;

m_y = y;

m_z = z;

m_h = h;

m_t = t;

}

}

Java 接口:

public  void getPara(Para_Tag tag);

JNI:

JNIEXPORT void  JNICALL Java_getPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

{

Para_Tag  tag;

getPara(&tag);// 取得C++/C中Para_Tag结构体的值

// 给java的Para_Tag class赋值

jclass DataCls = env->FindClass("com/Para_Tag"); // 通过class path找到class的标识

/*  对class中的每个变量逐一赋值 */

jfieldID dataId = env->GetFieldID(DataCls, "m_x", "I");

env->SetIntField(obj, dataId,tag.x);

dataId = env->GetFieldID(DataCls, "m_y", "S");

env->SetShortField(obj, dataId,tag.y);

/*  注意C++中的char * 类型如何通过JNI转换为Java的String  */

dataId = env->GetFieldID(DataCls, "m_z", "Ljava/lang/String;");

jstring strTmp = env->NewStringUTF((char *)tag.az);

env->SetObjectField(objdata, dataId, strTmp);

dataId = env->GetFieldID(DataCls, "m_h", "C");

env->SetCharField(obj, dataId,tag.h);

dataId = env->GetFieldID(DataCls, "m_t", "J"); // 注意long对应的签名是J,不是L

env->SetLongField(obj, dataId,tag.t);

}

上面这种做法是ok的,但是效率太低,每调用一次vm的env函数就会和虚拟机交互一次,,和虚拟机交互次数太多,有没有什么办法提高效率。

有,那就是如果对class中的多个成员变量都要赋值的话可以调用java的构造函数赋值,这样不管有多少个函数,只会和虚拟机交互一次,会大大提高效率。

修改后用构造函数赋值的例子如下:

JNIEXPORT void  JNICALL Java_getPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

{

Para_Tag  tag;

getPara(&tag);//取得C++/C中Para_Tag结构体的值

jclass DataCls = env->FindClass("com/Para_Tag"); //通过class path找到class的标

jmethodID RtnInitId = env->GetMethodID(DataCls, "", "(ISLjava/lang/String;CJ)V");

jstring strTmp = env->NewStringUTF((char *)tag.az);

env->CallVoidMethod(obj, RtnInitId, tag.x, tag.y,strTmp,tag.h,tag.t);

}

这里用到了C++/C中调用Java中的构造函数,实际上C++/C中还可以调用Java中的其它函数,后面会提到。

2.C++/C指针作为输入参数

这种情况下就要具体问题,具体分析了。

如果C++/C代码需要的仅仅是一个地址,且C++/C不会回传给值给Java,那么Java就传递一个int型的数即可。

例如:

C++/C:    void setValue(int  *ps32Addr,int value);

仅仅是给一个地址写值,那么

Java:public void setValue(int s32Addr,int value);

JNI:

JNIEXPORT void  JNICALL Java_setValue_ 1native (JNIEnv *env, jclass thiz, jint s32Addr,jint value)

{

int *ps32Addr = (int *)s32Addr;

setValue(ps32Addr,value);

}

如果C++/C的指针含有从Java中传递的数据信息,就需做如下处理:

typedef struct _Para_tag

{

int x;

short y;

char az[100];

char h;

}Para_Tag;

C++/C : void setPara(Para_Tag *pstTag)

Java:

public class Para_Tag

{

int x;

short y;

String z;

char h;

long t;

}

public void setPara(Para_Tag   tag);

JNI:

JNIEXPORT void  JNICALL Java_setPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

{

Para_Tag  tag;

jclass DataCls = env->FindClass("com/Para_Tag");

jfieldID dataId = env->GetFieldID(DataCls, "x", "I");

tag.x = env->GetIntField(obj, dataId);

dataId = env->GetFieldID(DataCls, "y", "S");

tag.y = env->GetShortField(obj, dataId);

dataId = env->GetFieldID(DataCls, "z", "Ljava/lang/String;");

jstring jstr = (jstring)env->GetObjectField(obj, dataId);

const char* str;

jboolean isCopye = false;

if(NULL != jstr)

{

str = env->GetStringUTFChars(jstr, &isCopye);

}

if(str == NULL)

{

return;

}

strncpy(tag.az,str,100);

tag.az[99] = '\0';

dataId = env->GetFieldID(DataCls, "h", "C");

tag.h = env->GetCharField(obj, dataId);

dataId = env->GetFieldID(DataCls, "t", "J");

tag.t = (jlong)env->GetLongField(obj, dataId);

setPara(&tag);

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值