栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

通过JNI实现Java和C++对象的相互转换,及封装小技巧

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

通过JNI实现Java和C++对象的相互转换,及封装小技巧

本文通过一个简单的例子,说明Java如何向C++传递对象类型,C++如何返回对象类型到Java,即Java和C++对象的相互转换。

java层类及native方法定义
com.mm.exmple;

//返回类
class ReturnInfo{
    public String host;
	public int port;
}
	
//输入类
class InputInfo{
	public String seq;
	public int num;
}
	
//native交互方法
public static native ReturnInfo getInfoFromCPP(InputInfo info);
C++层结构体及方法定义
//返回结构体
struct ReturnInfo
{
    std::string host;
    int port;
};

//入参结构体
struct InputInfo
{
    std::string seq;
    int num;
};

ReturnInfo getInfo(InputInfo info)
{
    ReturnInfo info;
    //do something;
    info.host = "127.0.0.1";
    info.port = 8080;

    return info;
}
JNI层接口定义与实现
//JNI方法声明,需要和Java层的native方法名称、参数、返回值相匹配
JNIEXPORT jobject JNICALL Java_com_mm_example_getInfoFromCPP(JNIEnv *env, jclass cls, jobject info);

//JNI方法实现,完成Java和C++的交互
JNIEXPORT jobject JNICALL
Java_com_mm_example_getInfoFromCPP
(JNIEnv *env, jclass cls, jobject info)
{
    //java对象jobject入参转换为C++结构体对象
    // 1)获取java InputInfo对象的jclass;
    jclass  inputInfoCls	= env->FindClass("com/mm/example/InputInfo");

    // 2)获取java对象的字段ID,注意字段名称和签名;
    jfieldID seqId  = env->GetFieldID(inputInfoCls, "seq", "Ljava/lang/String;");
    // 3)根据字段ID获取该字段的值;
    jstring seq = (jstring)env->GetObjectField(info, seqId);

    // 其他字段同上;
    jfieldID numId  = env->GetFieldID(inputInfoCls, "num", "I");
    jint num = (jstring)env->GetObjectField(info, numId);

    InputInfo inputInfo;
    // Java jstring类型转C++ char *类型
    char* szSeq = (char*)env->GetStringUTFChars(seq, 0);
    inputInfo.seq = szSeq;
    env->ReleaseStringUTFChars(seq,	szSeq);

    // 基础类型可直接赋值;
    inputInfo.num = num;

    //调用c++方法,得到C++返回结构体对象;
    ReturnInfo retInfo = getInfo(InputInfo info);

    //C++结构体对象转换为java对象;
    // 1)获取java ReturnInfo对象的jclass;
    jclass jReturnClass = env->FindClass("com/mm/example/ReturnInfo");
    // 2)获取构造方法ID;
    jmethodID jmId = env->GetMethodID(jReturnClass, "", "()V");
    // 3)通过构造方法ID创建Java ReturnInfo对象;
    jobject jReturnObj = env->NewObject(jReturnClass, jmId);
    // 4)获取ReturnInfo对象的字段ID;
    jfieldID hostId   = (env)->GetFieldID(jReturnClass, "host", "Ljava/lang/String;");
    jfieldID portId      = (env)->GetFieldID(jReturnClass, "port", "I");

    // 5)通过字段ID给每个字段赋值
    jstring host = env->NewStringUTF(retInfo.host.c_str());
    env->SetObjectField(jReturnObj, hostId, host);
    env->SetIntField(jReturnObj, portId, (jint)retInfo.port);

    // 返回Java对象;
	return jReturnObj;

}

至此,就实现了Java对象和C++对象之间的互相转换。

总结 Java对象转C++对象流程
  1. 获取Java对象的jclass;

  2. 获取Java对象的字段ID,注意字段名称和签名;

  3. 根据字段ID获取该字段的值;

  4. JNI类型和C++类型转换;

  5. 对C++对象进行赋值;

C++对象转Java对象流程
  1. 获取Java对象的jclass;

  2. 获取构造方法ID;

  3. 通过构造方法ID创建Java对象;

  4. 获取Java对象的字段ID;

  5. C++类型和JNI类型转换;

  6. 通过字段ID给每个字段赋值;

    Java对象和C++对象之间的互相转换看起来很复杂,其实套路都是固定的,实现起来挺简单的,但麻烦。如果使用比较多的话,可以把重复部分封装成函数,书写和阅读都比较方便。

比如:

获取Java对象的jstring
jstring GetStuStringField(JNIEnv* env, jobject valueObject,  jclass clsStu, const char* fieldName)
{
    jfieldID idValue  = env->GetFieldID(clsStu, fieldName, "Ljava/lang/String;");
    return (jstring)env->GetObjectField(valueObject, idValue);
}

其他Java对象的字段可参考这种实现。

jstring转c++ std::string
void CoverStringTostring( JNIEnv* env, jstring jValue, std::string& vValue )
{
    if ( jValue == NULL )
    {
        // log error!
        return;
    }
    
    char* szValu = (char*)env->GetStringUTFChars(jValue, 0);
    if (szValu != NULL) {
        vValue = szValu;
    } else {
        // log error!
    }
    env->ReleaseStringUTFChars(jValue,	szValu);
}

其他类型的转换也可以参考这种实现,封装成函数,方便调用。

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/954650.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号