通过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, "<init>", "()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);
}

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

 

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值