java 通过jni 向 c 传递一个 java 对象, c 如何取得这个对象的属性值?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 通过jni 向 c 传递一个 java 对象, c 如何取得这个对象的属性值?相关的知识,希望对你有一定的参考价值。

java 通过jni 向 c 传递一个 java 对象(简单对象 只有属性,java对这个对象属性进行赋值后传递给c), c 如何取得这个对象的属性值?
取得后,如何 对这个属性重新赋值并返回?

对于java传递进来的java对象模型,c要加载java类的原型,根据创建相应的c对象,获取java对象的方法的id,然后调用java对象的方法。比如有个java类customer对象作为jni参数传递到c程序,customer有方法String getName()。
JNIEXPORT jobject JNICALL Java_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomer
(JNIEnv *env, jobject, jobject customer)
jmethodID methodId;
//获得customer对象的句柄
jclass cls_objClass=env->GetObjectClass(customer);
//获得customer对象中特定方法getName的id
methodId=env->GetMethodID(cls_objClass,"getName","()Ljava/lang/String;");
//调用customer对象的特定方法getName
jstring js_name=(jstring)env->CallObjectMethod(customer,methodId,NULL);
...


然后C向java传递对象方法如下:
JNIEXPORT jobject JNICALL Java_perfecter_jni_LoadJni_getJavaObj(JNIEnv* env,
jobject obj)
jclass clazz=env->FindClass("perfecter/jni/MyObj");

if(clazz==0)
return 0;

jobject jobj=env->AllocObject(clazz);

jfieldID fieldId=env->GetFieldID(clazz,"name","Ljava/lang/String;");

env->SetObjectField(jobj,fieldId,env->NewStringUTF("wahaha"));

return jobj;


java对应的native方法申明public static native MyObj getJavaObj();
参考技术A 可以用json。就是将一个对象序列化成一种格式的字符串。然后在c进行解析,或者编制。

JNI内通过参数形式从C/C++中传递string类型数据至Java层

目录

0  前言

1 string类型参数形式传值

2 测试和结果


0  前言

        类似之前我写过的两篇文章:一篇介绍了在JNI中基础类型int的传值方式;一篇详细梳理了在JNI层中多维数组的多种传值方式。

JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理_nanke_yh的博客-CSDN博客

JNI内形参从C代码中获取返回值并返回到Java层使用-CSDN博客

        这篇则主要是讲JNI中String类型的数据如何通过参数的形式传递数据值。

1 string类型参数形式传值

        对于JNI层传递string类型数据的网络检索,出现的并不多。大多都是讲通过return方式进行内容传递的,大家大可参考:JNI String类型 - 知乎 (zhihu.com),内部有相关理论介绍可以了解。

        通过参数形式传递string类型数据具体借鉴了下文:JNI 通过形参String返回数据的方法_jni string 参数返回_Cosmo_Wang1989的博客-CSDN博客

本文具体的其实也是将string传递成StringBuffer类型,即以StringBuffer作为参数传入获取内部string数据。如此在c/c++中就有了以下的实现代码:(具体的分析解释看代码中的注释)

//最终实际传出的数据类型为StringBuffer
JNIEXPORT jint Java_com_test_java_JNItest_testString
  (JNIEnv *env, jobject, jobject result)

	string  sstr = "Hello world!"; 
	//str.c_str()转成const char*
	const char* str = sstr.c_str();
		
	//jstring的类型
	jclass strClass = (env)->FindClass("Ljava/lang/String;");
	//methodID
	jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
	//通过字符数组存储字符串 
	jbyteArray bytes = (env)->NewByteArray(strlen(str));
	(env)->SetByteArrayRegion(bytes, 0, strlen(str), (jbyte*)str);
	//规定字符为UTF-8
	jstring encoding = (env)->NewStringUTF("UTF-8"); 
	//得到jstring类型的数据   //若采用return方式传出的话,则可以直接返回temp。
	jstring temp=(jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);
	
	//获取需要传出去result参数类型
	jclass outputJcls = env->GetObjectClass(result);
	
	//根据result数据类型获取append操作的methodID
	jmethodID appendJmId = env->GetMethodID(outputJcls, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
	//再根据methodID将jstring传到参数result上
	 env->CallObjectMethod(result, appendJmId, temp);

	return 0;

2 测试和结果

        针对上述的代码实现,在java层调用native并测试:

public native int testString(StringBuffer result);

        main函数内测试代码:

        JNItest JNI = new JNItest();
        StringBuffer output = new StringBuffer();

        int rnt = JNI.testString(output);
        //StringBuffer通过toString即可转为String
        System.out.println(output.toString());

        其中StringBuffer通过toString即可转为String,关于Java中这些字符串类型之间关系可参考:Java中字符数组、String类、StringBuffer三者的相互转换 - 功夫 熊猫 - 博客园 (cnblogs.com)

        最后运行结果如下:

         根据结果可以发现,output获取了c/c++层内部sstr的数据内容了。

以上是关于java 通过jni 向 c 传递一个 java 对象, c 如何取得这个对象的属性值?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JNI(更具体地说是 Android NDK)时,Java 是不是通过引用或值传递给 C

JNI内通过参数形式从C/C++中传递string类型数据至Java层

Android JNI 传递对象

将参数从 C/C++ JNI 传递到 Java 并获取修改后的值

JNI维数组:将二维数组从java传递给c

JNI C/C++ Callback from JAVA