首先来看一下C/C++中怎么创建Java对象:在JNIEnv中有两种方法是用来创建Java对象的:
第一种方法:
jobject NewObject(jclass clazz , jmethodID methodID, ....):
参数解释:
clazz:这个很简单,就是需要创建的Java对象的Class对象
methodID:这个是传递一个方法的ID,想一想Java对象在创建的时候,需要执行什么方法呢?对,没错那就是构造方法
第三个参数:是构造函数需要传入的参数值(默认的构造方法是不需要传入这个参数的)
所以我们在创建Java对象的时候之前要做的工作就是要获取这个对象的class对象,然后再获取该对象的构造方法,想要获取方法的id,就需要方法的签名,因为构造方法没有返回值,所以我们认为类的默认构造方法的返回值类型的签名始终是“()V”(因为默认的构造方法是没有参数的),方法的名称始终为“
”
例子:在C++中构造Java中的Date对象,并且调用它的getTime()方法打印当前时间
Java中的代码不需要改变,主要是C++代码中的改写:
[cpp]
- #include
- #include com_jni_demo_JNIDemo.h
-
- JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj)
- {
- //获取Java中Date对象的Class对象
- jclass clazz_date = env->FindClass(java/util/Date);
- //获取构造方法的id
- jmethodID mid_date = env->GetMethodID(clazz_date,
,()V);
- //生成Date对象
- jobject now = env->NewObject(clazz_date,mid_date);
- //获取Date对象中的getTime方法的id
- jmethodID mid_date_getTime = env->GetMethodID(clazz_date,getTime,()J);
- //调用getTime方法返回时间
- jlong time = env->CallLongMethod(now,mid_date_getTime);
- //打印时间,这里要注意的是不能使用cout输出了,因为cout并没有对__int64的输出进行重载,要输出的话用printf(%I64d,time);
- printf(%I64d,time);
- }
编译成.dll文件,在Eclipse中运行结果如下:
这个输出的时间没有进行格式化处理。
第二种方法:
创建一个对象:就是用AllocObject
使用函数AllocObject可以根据传入的jclass创建一个Java对象,但是他的状态时非初始化的,在是哟个这个对象之前绝对要用CallNonvirtualVoidMethod来调用该jclass的构造函数,这样就可以延迟构造函数的调用,这一部分用的很少,只做简单的说明:
Java中的代码不做任何修改,C++代码中修改成如下:
[cpp] view plaincopy
- #include
- #include com_jni_demo_JNIDemo.h
-
- JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj)
- {
- //获取java中的Date对象
- jclass clazz_date = env->FindClass(java/util/Date);
- jmethodID methodID_str = env->GetMethodID(clazz_date,
,()V);
- jobject now = env->AllocObject(clazz_date);
- //调用构造方法
- env->CallNonvirtualVoidMethod(now,clazz_date,methodID_str);
- //获取Date对象中的getTime方法的id
- jmethodID mid_date_getTime = env->GetMethodID(clazz_date,getTime,()J);
- //调用getTime方法返回时间
- jlong time = env->CallLongMethod(now,mid_date_getTime);
- //打印时间,这里要注意的是不能使用cout输出了,因为cout并没有对__int64的输出进行重载,要输出的话用printf(%I64d,time);
- printf(%I64d,time);
- } 这种方式是很少用的!
下面来看一下C/C++中如何操作Java中的字符串
首先来看一下JNIEnv中的一些C++方法:
1.获取字符串的长度:
参数:j_msg:是一个jstring对象
env->GetStringLength(jstring j_msg);
2.将jstring对象拷贝到const jchar*指针字符串
参数:j_msg:是一个jstring对象,start是拷贝字符串的开始位置,end是拷贝字符串的结束位置,jstr是目标指针字符串
env->GetStringRegion(jstring j_msg , int start , int end , const jchar* jstr);
3.生成一个jstring对象
参数:jstr是字符串指针,size是字符串长度
这个方法可以认为是将字符串指针jstr转化成字符串对象jstring
env->NewString(const jchar* jstr , int size);
4.将jstring对象转化成const jchar*字符串指针
参数:j_msg是字符串对象
env->GetStringChars(jstring j_msg , NULL);
其对应的释放内存指针的方法:
参数:j_msg是jstring对象,jstr是字符串指针
ReleaseStringChars(jstring j_msg , const jchar* jstr);
5.将jstring对象转化成const jchar*字符串指针
参数:j_msg是字符串对象
这个方法和第四个方法是一样的功能
env->GetStringCritical(jstring j_msg , NULL);
其对应的释放内存指针的方法:
env->ReleaseStringCritical(jstring j_msg , const jchar* jstr);
下面来看一下实例:在Java中定义一个String属性,通过控制台输入值,然后定义一个本地方法callCppFunction,在C++中这个方法的实现就是:获取到Java中这个字符串属性,将其进行倒序操作然后,然后再Java中输出:
先来看一下Java中的代码:
[java]
- package com.jni.demo;
-
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
-
- public class JNIDemo {
-
- //定义一个本地方法
- public native void callCppFunction();
- /