JNI/NDK入门指南之C/C++结构体和Java对象转换方式二

   JNI/NDK入门指南之C/C++结构体和Java对象转换方式二


   在前面的篇章C/C++结构体和Java对象之间通过Jni相互转换方式一中已经介绍了一种方法,可能有些对Android源码或者Jni比较熟悉的读者会说,在源码里面很少会用到前面的方法,而是通过Jni里面的jfieldID和jmethodID直接操作Java对象来进行相转换。下面开启本篇介绍之旅,方式二介绍。



一.方法介绍

   在这里将要使用到是比较传统的方法,借助NDK中jni.h头文件中定义的方法,直接操作通过Jni传递过来的Java层的Object对象,获取object中jfieldID域值然后赋值到C/C++中Struct结构体中这样就完成了Java对象对C/C++结构体的转换。然后对Object中的jfieldID域进行相关的赋值操作,这样就完成了相关的相互的转换。



二.具体步骤

   在前面的章节已经介绍了,具体使用什么方法。那么在本章节里面将介绍具体的步骤,那么,下面来开始我们的介绍。


2.1 需要转换的数据

   本篇的标题是C/c++结构体和Java对象之间的转换,那么下面介绍我们要相互转换的数,这里只是为了做演示使用,至于数据还可以进行扩展,或者学完此种方法以后读者也可以亲自操作实践一把。

(1) C/C++结构体

//对应om.pax.object2struct.JavaBean的数据
typedef struct{
	bool 		boolValue;   //boolean
	char 		charValue;	 //char 
	double 		doubleValue; //double
	int         intValue;	//int
	char        arrayValue[4]; //byte[]
	int 		double_dimen_array[2][2]; // int[][]
	const char * stringValue;
	const char * message; // String	
}JNI_JavaBean;



//对应com.pax.object2struct.JavaBean$InnerClass的域和方法
typedef struct{
	jclass clazz;
	jfieldID message;
	jmethodID constructor;
}InnerClass_t;

//对应com.pax.object2struct.JavaBean的域和方法
typedef struct {
	jclass clazz;

	jfieldID boolValue;
	jfieldID charValue;
	jfieldID doubleValue;
	jfieldID intVaule;
	jfieldID byteArray;
	jfieldID double_dimen_array;
	jfieldID stringValue;
	jfieldID inner_message;

	jmethodID constructor;
	
}JavaBean_t;

(2) Java类

package com.pax.object2struct;

public class JavaBean {
    public boolean boolValue = false; // boolean类型
    public char charValue  = 'A'; // char类型
    public double doubleValue = 100; // double类型
    public int intValue = 100; // 整形
    public byte[] array = {0, 1, 2, 3}; // byte数组

    public int[][] mDoubleDimenArray = {
            {10,10},
            {20,20}
    }; // 二维数组
    public String stringValue = "Hello!";
    public InnerClass mInnerClass = new InnerClass(); // 静态内部类

    static class InnerClass {
        public String mMessage = "Im from Java!";// 字符串

        @Override
        public String toString() {
            return "InnerClass [mMessage=" + mMessage + "]";
        }

    }

    @Override
    public String toString() {
        return "JavaBean [boolValue=" + boolValue + ", charValue=" + charValue
                + ", doubleValue=" + doubleValue + ", intValue=" + intValue
                + ", array=" + array.toString() + ", mDoubleDimenArray="
                + mDoubleDimenArray.toString() + ", stringValue=" + stringValue
                + ", mInnerClass=" + mInnerClass + "]";
    }

}


2.2 具体实现

   前面的章节介绍了,需要转换的数据,那么在这个章节将要介绍具体的步骤。


2.2.1 Jni接口的定义

public class JniTransfer {

    // 将C/C++结构体转为Java类
    public static native JavaBean getJavaBeanFromNative();

    //将Java对象转换成C/C++结构体
    public static native void transferJavaBeanToNative(JavaBean javaBean);

    // 加载jni库
    static {
        System.loadLibrary("java2native-transfer");
    }
}

2.2.2 Java端的实现

   这个比较简单,主要就是通过Jni将Java对象传递到Jni层进行相关的转换,然后加以打印。就不加以赘述了,因为确实代码量比较少太简单,我想讲解也没有啥好讲解的。

    private void getJavaBeanFromC() {
        JavaBean javaBean = JniTransfer.getJavaBeanFromNative();
        Log.d("JniTransfer", javaBean.toString());
    }

    private void javaBeanToStruct() {
        JavaBean javaBean = new JavaBean();
        JniTransfer.transferJavaBeanToNative(javaBean);
    }

2.2.3 Jni端的实现

   这个比前面的第一种方法要复杂一点,因为涉及到本地Native方法的注册,相关类信息的注册。下面我们就一个步骤一个步骤的类详细介绍:

2.2.3.1 Jni动态注册
static JNINativeMethod gMethods[] = {
	{"getJavaBeanFromNative", "()Lcom/pax/object2struct/JavaBean;",(void*)Java_com_pax_object2struct_JniTransfer_getJavaBeanFromNative },
	{"transferJavaBeanToNative", "(Lcom/pax/object2struct/JavaBean;)V",(void*)Java_com_pax_object2struct_JniTransfer_transferJavaBeanToNative },
};	
//动态注册Native方法
static int register_native_interface(JNIEnv * env){
	jclass clazz;
	clazz = env->FindClass(kClassPathName);

	if(clazz == NULL)
		return JNI_FALSE;

	if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0){
	        return JNI_FALSE;
	 }

	
	return JNI_TRUE;
}


jint JNI_OnLoad(JavaVM * vm, void * reserved){
	JNIEnv * env = NULL;
	jint result = -1;

	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
	    LOGE(TAG, "ERROR: GetEnv failed\n");
	    goto bail;
	}
	assert(env != NULL);
	if (register_native_interface(env) < 0) {
	    LOGE(TAG,"ERROR: native registration failed\n");
	    goto bail;
	}
	register_classes(env);

	result = JNI_VERSION_1_4;
	bail:
	return result;
	
}

2.2.3.2 注册类信息
static JavaBean_t javaBean_t;
static InnerClass_t innerClass_t;
#define ARRAY_LEN(x) ((int) (sizeof(x) / sizeof((x)[0])))


static int dump_JavaBean_Info(JNI_JavaBean * javaBean){
	int i =0;
	int lenght = 0;

	LOGE(TAG, "+++ dump javaBean info start +++\n");

	LOGE(TAG, "+++ 		boolValue : %d 		+++\n", javaBean->boolValue);
	LOGE(TAG, "+++ 		charValue : %c 		+++\n", javaBean->charValue);
	LOGE(TAG, "+++ 		doubleVaule : %lf 	+++\n", javaBean->doubleValue);
	LOGE(TAG, "+++ 		intValue : %d		+++\n", javaBean->intValue);

	lenght = ARRAY_LEN(javaBean->arrayValue);
	for(i = 0; i < lenght; i++)
	{
		LOGE(TAG, "+++      byte[%d] : %d		+++\n", i, javaBean->arrayValue[i]);
	}

	for(i =0 ; i <2; i++){
		for(int j = 0; j <2; j++)
		{
			LOGE(TAG, "+++      byte[%d] : %d		+++\n", i, javaBean->arrayValue[i]);
			LOGE(TAG, "+++      double[%d][%d]: %d  +++\n", i, j, javaBean->double_dimen_array[i][j]);
		}
	}

	LOGE(TAG, "+++		stringValue : %s	+++\n", javaBean->stringValue);
	LOGE(TAG, "+++		inner_message : %s	+++\n", javaBean->message);
	
	LOGE(TAG, "+++ dump javaBean info end   +++\n");
}

static int find_class(JNIEnv * env, const char *className, jclass * classOut)
{
	jclass clazz = env->FindClass(className);
	if(clazz == NULL)
	{
		LOGE(TAG,"Can't find %s\n", className);
		return -1;
	}
	*classOut = (jclass) env->NewGlobalRef(clazz); // 这里必须新建一个全局的引用
	return 0;
	
}
static int get_field(JNIEnv * env, jclass clazz, const char *name, const char *sig, jfieldID * field_out)
{
    jfieldID filed = env->GetFieldID(clazz, name, sig);
    if (filed == NULL) {
        LOGE(TAG, "Can't find. filed name: %s, sig: %s", name, sig);
        return -1;
    }
    *field_out = filed;
    return 0;

}

static void register_inner_class(JNIEnv * env)
{
	int ret = find_class(env, "com/pax/object2struct/JavaBean$InnerClass", &innerClass_t.clazz);
	if(ret != 0)
	{
		LOGE(TAG,"register_inner_class failed, please check you code!\n");
		return;
	}

	jclass inner_clazz = innerClass_t.clazz;
	// 获取构造方法    
	innerClass_t.constructor = env->GetMethodID(inner_clazz, "<init>", "()V");   
	// 获取成员    
	get_field(env, inner_clazz, "mMessage", "Ljava/lang/String;", &innerClass_t.message);

}

static void register_javaBean_class(JNIEnv * env)
{
	int ret = find_class(env, "com/pax/object2struct/JavaBean", &javaBean_t.clazz);
	if(ret != 0)
	{
		LOGE(TAG,"register_JavaBean_class failed, please check you code!\n");
		return;
	}


	jclass javaBean_clazz = javaBean_t.clazz;

	//在Jni中获取构造方法
	javaBean_t.constructor = env->GetMethodID(javaBean_clazz, "<init>", "()V");
	//获取成员方法
	//Signature: (ZCDI[B[[ILjava/lang/String;)V
	get_field(env, javaBean_clazz, "boolValue", "Z", &javaBean_t.boolValue);
	get_field(env, javaBean_clazz, "charValue", "C", &javaBean_t.charValue);
	get_field(env, javaBean_clazz, "doubleValue", "D", &javaBean_t.doubleValue);
	get_field(env, javaBean_clazz, "intValue", "I", &javaBean_t.intVaule);
	get_field(env, javaBean_clazz, "array", "[B", &javaBean_t.byteArray);
	get_field(env, javaBean_clazz, "mDoubleDimenArray", "[[I", &javaBean_t.double_dimen_array);
	get_field(env, javaBean_clazz, "stringValue", "Ljava/lang/String;", &javaBean_t.stringValue);
	get_field(env, javaBean_clazz, "mInnerClass", "Lcom/pax/object2struct/JavaBean$InnerClass;", &javaBean_t.inner_message);
}	

static void register_classes(JNIEnv* env)
{
	register_javaBean_class(env);
	register_inner_class(env);
}

2.2.3.3 Java对象转换成C/C++结构体
/**
	java class  use jni transfer to c struct
**/

static void javaBean_java_2_c(JNIEnv *env , jobject javaBean_in, JNI_JavaBean * jni_JavaBean_out)
{
	if(javaBean_in == NULL)
	{
		LOGE(TAG,"javaBean_in is NULL, please check you input or code!\n");
		return;
	}

	LOGE(TAG,"Start javaBean_java_2_c fun\n");


	//get boolValue
	jni_JavaBean_out->boolValue = env->GetBooleanField(javaBean_in, javaBean_t.boolValue);

	//get charValue
	jni_JavaBean_out->charValue = env->GetCharField(javaBean_in, javaBean_t.charValue);

	//get doubleValue
	jni_JavaBean_out->doubleValue = env->GetDoubleField(javaBean_in, javaBean_t.doubleValue);

	//get intValue
	jni_JavaBean_out->intValue = env->GetIntField(javaBean_in, javaBean_t.intVaule);


	//get byte array
	jbyteArray byteArray = (jbyteArray)env->GetObjectField(javaBean_in, javaBean_t.byteArray);
	jbyte * byte_data = env->GetByteArrayElements(byteArray, 0);
	jsize length = env->GetArrayLength(byteArray);
	LOGE(TAG,"The byteArray len : %d\n", length);
	//copy data
	memcpy(jni_JavaBean_out->arrayValue, byte_data, length * sizeof(jbyte));


	//get double dimen int array
	jobjectArray objectArray = (jobjectArray)env->GetObjectField(javaBean_in, javaBean_t.double_dimen_array);
	length = env->GetArrayLength(objectArray);
	LOGE(TAG,"doublemin int array len : %d\n", length);
	for(int i = 0; i < length; i++)
	{
		jintArray intArray = (jintArray)env->GetObjectArrayElement(objectArray, i);
		jint * sub_int = env->GetIntArrayElements(intArray, 0);
		jsize sub_len = env->GetArrayLength(intArray); // 获取列数 	   
		LOGE(TAG,"sub_len: %d", sub_len);		
		memcpy(jni_JavaBean_out->double_dimen_array[i], sub_int, sub_len * sizeof(jint));		
		env->ReleaseIntArrayElements(intArray, sub_int, 0);
	}

	
	//get stringValue
	LOGE(TAG,"get StringValue\n");
	jstring stringValue = (jstring)env->GetObjectField(javaBean_in, javaBean_t.stringValue);
	jni_JavaBean_out->stringValue = env->GetStringUTFChars(stringValue, 0);
	
	

	//get inner class data
	LOGE(TAG,"get inner class data\n");
	jobject inner_object = env->GetObjectField(javaBean_in, javaBean_t.inner_message);
	jstring message = (jstring)env->GetObjectField(inner_object, innerClass_t.message);
	jni_JavaBean_out->message = env->GetStringUTFChars(message, 0);
}

2.2.3.4 C/C++结构体转换为Java对象
/**
	c struct use jni transfer to java class
**/
static jobject javaBean_c_2_java(JNIEnv *env , JNI_JavaBean * jni_JavaBean)
{
	if(jni_JavaBean == NULL)
	{
		LOGE(TAG,"javaBean_c_2_java failed, jni_JavaBean is NULL\n");
		return NULL;
	}
	LOGE(TAG,"javaBean_c_2_java\n");


	LOGE(TAG,"innerObject\n");
	//1.create InnerClass class
	jobject innerObject = env->NewObject(innerClass_t.clazz, innerClass_t.constructor);
	jstring message = env->NewStringUTF(jni_JavaBean->message);
	env->SetObjectField(innerObject, innerClass_t.message, message);

	LOGE(TAG,"javaBeanObject\n");
	//2.create JavaBean class
	jobject javaBeanObject = env->NewObject(javaBean_t.clazz, javaBean_t.constructor);

	
	//set boolValue
	env->SetBooleanField(javaBeanObject, javaBean_t.boolValue, jni_JavaBean->boolValue);

	LOGE(TAG,"set charValue\n");
	//set charValue
	env->SetCharField(javaBeanObject, javaBean_t.charValue, jni_JavaBean->charValue);

	
	LOGE(TAG,"set doubleVaule\n");
	//set doubleVaule
	env->SetDoubleField(javaBeanObject, javaBean_t.doubleValue, jni_JavaBean->doubleValue);

	LOGE(TAG,"set intValue\n");
	//set intValue
	env->SetIntField(javaBeanObject, javaBean_t.intVaule, jni_JavaBean->intValue);

	LOGE(TAG,"set StringValue\n");
	//set StringValue
	jstring stringValue = env->NewStringUTF(jni_JavaBean->stringValue);
	env->SetObjectField(javaBeanObject, javaBean_t.stringValue, stringValue);

	LOGE(TAG,"set byte[] array\n");
	//set byte[] array
	jsize length = ARRAY_LEN(jni_JavaBean->arrayValue);
	LOGE(TAG,"The byteArray len : %d\n", length);
	jbyteArray byteArray = env->NewByteArray(length);
	env->SetByteArrayRegion(byteArray, 0, length, (jbyte *)jni_JavaBean->arrayValue);
	env->SetObjectField(javaBeanObject, javaBean_t.byteArray, byteArray);


	LOGE(TAG,"set double dimen int array\n");
	//set double dimen int array
	//设置二维数组的时候需要要一定的技巧性
	length = ARRAY_LEN(jni_JavaBean->double_dimen_array);
	LOGE(TAG,"The double_dimen_array : %d\n", length);
	jclass clazz  = env->FindClass("[I");//一维数组的类
	jobjectArray double_int_array = env->NewObjectArray(length, clazz, NULL);


	
	for(int i = 0; i < length; i++)
	{
		jsize sub_len = ARRAY_LEN(jni_JavaBean->double_dimen_array[i]);
		LOGE(TAG,"The sub[%d] len: %d\n", i, sub_len);
		jintArray intArray = env->NewIntArray(sub_len);
		env->SetIntArrayRegion(intArray, 0, sub_len, jni_JavaBean->double_dimen_array[i]);
		env->SetObjectArrayElement(double_int_array, i, intArray);
	}
	env->SetObjectField(javaBeanObject, javaBean_t.double_dimen_array, double_int_array);

	//set innerClass 
	env->SetObjectField(javaBeanObject, javaBean_t.inner_message, innerObject);

	return javaBeanObject;
	
}

2.2.3.5 具体使用

/*
 * Class:     com_pax_object2struct_JniTransfer
 * Method:    getJavaBeanFromNative
 * Signature: ()Lcom/pax/object2struct/JavaBean;
 */
JNIEXPORT jobject JNICALL Java_com_pax_object2struct_JniTransfer_getJavaBeanFromNative
  (JNIEnv * env, jclass clazz)
{
	 JNI_JavaBean javaBean= {
			true,
			'c',
			1,
			2,
			{1, 2, 3, 4},
			{
				{5,6},
				{7,8}
			},
			"Im StringValue",
			"Im message",
		};


		
	dump_JavaBean_Info(&javaBean);
	jobject obj = javaBean_c_2_java(env, &javaBean);
	return obj;
}

/*
 * Class:     com_pax_object2struct_JniTransfer
 * Method:    transferJavaBeanToNative
 * Signature: (Lcom/pax/object2struct/JavaBean;)V
 */
JNIEXPORT void JNICALL Java_com_pax_object2struct_JniTransfer_transferJavaBeanToNative
  (JNIEnv * env, jclass clazz, jobject object)
{
	JNI_JavaBean   jni_JavaBean;
	javaBean_java_2_c(env, object, &jni_JavaBean);	
	dump_JavaBean_Info(&jni_JavaBean);
}



三.成果演示

   在前面的章节里面,我们将原理和步骤都已经交代和讲解OK了,那么到了最终的步骤了就是见证奇迹的时刻到了,看下我们的效果。是不是已经OK了.

λ adb logcat  -s JniTransfer
--------- beginning of main
--------- beginning of system
12-02 17:13:39.640 27863 27911 E JniTransfer: getJavaBeanFromC
12-02 17:13:39.647 27863 27911 I JniTransfer: +++ 	   dump javaBean info start +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      boolValue : 1            +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      charValue : c            +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      doubleVaule : 1.000000   +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      intValue : 2             +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[0] : 1              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[1] : 2              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[2] : 3              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[3] : 4              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[0] : 1              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      double[0][0]: 5          +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[0] : 1              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      double[0][1]: 6          +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[1] : 2              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      double[1][0]: 7          +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      byte[1] : 2              +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++      double[1][1]: 8          +++
12-02 17:13:39.647 27863 27911 I JniTransfer: +++ stringValue : Im StringValue  +++
12-02 17:13:39.648 27863 27911 I JniTransfer: +++ inner_message : Im message    +++
12-02 17:13:39.648 27863 27911 I JniTransfer: +++      dump javaBean info end   +++
12-02 17:13:39.648 27863 27911 I JniTransfer: javaBean_c_2_java
12-02 17:13:39.648 27863 27911 I JniTransfer: innerObject
12-02 17:13:39.648 27863 27911 I JniTransfer: javaBeanObject
12-02 17:13:39.648 27863 27911 I JniTransfer: set charValue
12-02 17:13:39.648 27863 27911 I JniTransfer: set doubleVaule
12-02 17:13:39.648 27863 27911 I JniTransfer: set intValue
12-02 17:13:39.648 27863 27911 I JniTransfer: set StringValue
12-02 17:13:39.648 27863 27911 I JniTransfer: set byte[] array
12-02 17:13:39.648 27863 27911 I JniTransfer: The byteArray len : 4
12-02 17:13:39.648 27863 27911 I JniTransfer: set double dimen int array
12-02 17:13:39.648 27863 27911 I JniTransfer: The double_dimen_array : 2
12-02 17:13:39.648 27863 27911 I JniTransfer: The sub[0] len: 2
12-02 17:13:39.648 27863 27911 I JniTransfer: The sub[1] len: 2
12-02 17:13:39.649 27863 27911 D JniTransfer: JavaBean [boolValue=true, charValue=c, doubleValue=1.0, intValue=2, array=[B@ec430b3, mDoubleDimenArray=[[I@dd17670, stringValue=Im StringValue, mInnerClass=InnerClass [mMessage=Im message]]
12-02 17:13:39.649 27863 27911 E JniTransfer:
12-02 17:13:39.649 27863 27911 E JniTransfer: javaBeanToStruct
12-02 17:13:39.649 27863 27911 I JniTransfer: Start javaBean_java_2_c fun
12-02 17:13:39.650 27863 27911 I JniTransfer: The byteArray len : 4
12-02 17:13:39.650 27863 27911 I JniTransfer: doublemin int array len : 2
12-02 17:13:39.650 27863 27911 I JniTransfer: sub_len: 2
12-02 17:13:39.650 27863 27911 I JniTransfer: sub_len: 2
12-02 17:13:39.650 27863 27911 I JniTransfer: get StringValue
12-02 17:13:39.650 27863 27911 I JniTransfer: get inner class data
12-02 17:13:39.650 27863 27911 I JniTransfer: +++ 	   dump javaBean info start +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      boolValue : 0           	+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      charValue : A           	+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++ doubleVaule : 100.000000     	+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      intValue : 100          	+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[0] : 0              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[1] : 1              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[2] : 2              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[3] : 3              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[0] : 0              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      double[0][0]: 10  		+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[0] : 0              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      double[0][1]: 10  		+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[1] : 1              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      double[1][0]: 20  		+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      byte[1] : 1              +++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      double[1][1]: 20  		+++
12-02 17:13:39.650 27863 27911 I JniTransfer: +++      stringValue : Hello!    	+++
12-02 17:13:39.651 27863 27911 I JniTransfer: +++ inner_message : Im from Java! +++
12-02 17:13:39.651 27863 27911 I JniTransfer: +++   dump javaBean info end      +++


写在最后

   如上就将C/C++结构体和Java对象之间通过Jni相互转换的两种方式介绍完了,这两种都是比较常见的方法,读者朋友们掌握了这两种方法以后,再难的转换无外乎也可以使用这两种方式。最后希望本篇能对实际工作中的你有一定的帮助作用。最后附上实例工程C_Java_Transfer.zip

发布了89 篇原创文章 · 获赞 92 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/tkwxty/article/details/103350464
今日推荐