本文将通过实例来说明如何在jni 访问Java的类和成员。开始先介绍所有对象分类的方法,最后才是实例说明。
访问对象的属性和方法
1、实例属性的访问
jfieldID GetFieldID (JNIEnv*env, jclass clazz, const char *name, const char*sig);
功能:返回类的实例(非静态)域的属性 ID。该域由其名称及签名指定。访问器函数的Get<type>Field及 Set<type>Field
系列使用域 ID检索对象域。GetFieldID()不能用于获取数组的长度域。应使用GetArrayLength()。
参数: env:JNI接口指针。
clazz:Java类对象。
name:该属性的Name名称
sig: 该属性的域签名。
返回值:属性ID。如果操作失败,则返回NULL。
抛出: NoSuchFieldError:如果找不到指定的域。
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败。
OutOfMemoryError:如果系统内存不足。
Get<type>Field例程
NativeType Get<type>Field (JNIEnv*env, jobject obj, jfieldIDfieldID);
功能:该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用GetFieldID()而得到的域 ID 指定。
参数: env:JNI接口指针。
obj:Java对象(不能为 NULL)。
fieldID:有效的域 ID。
返回值: 属性的内容。
Get<type>Field例程名 本地类型
GetObjectField() jobject
GetBooleanField() jboolean
GetByteField() jbyte
GetCharField() jchar
GetShortField() jshort
GetIntField() jint
GetLongField() jlong
GetFloatField() jfloat
GetDoubleField() jdouble
Set<type>Field 方法族
void Set<type>Field (JNIEnv *env, jobject obj, jfieldIDfieldID, NativeTypevalue);
功能:该访问器例程系列设置对象的实例(非静态)属性的值。要访问的属性由通过调用SetFieldID()而得到的属性 ID指定。
参数: env:JNI接口指针。
obj:Java对象(不能为 NULL)。
fieldID:有效的域 ID。
value:域的新值。
方法族 如下:
Set<type>Field 方法族 本地类型
SetObjectField() jobject
SetBooleanField() jboolean
SetByteField() jbyte
SetCharField() jchar
SetShortField() jshort
SetIntField() jint
SetLongField() jlong
SetFloatField() jfloat
SetDoubleField() jdouble
2、静态属性的访问 :也存在相同的方法,
jfieldID GetStaticFieldID (JNIEnv *env,jclass clazz, const char *name, const char*sig);
NativeType GetStatic<type>Field (JNIEnv*env,jclass classzz , jfieldIDfieldID);
void SetStatic<type>Field (JNIEnv *env,jclassclasszz, jfieldIDfieldID, NativeTypevalue);
它们与实例属性的唯一区别在于第二个参数jclass classzz代表的是类引用,而不是类实例。
3、调用实例方法
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char*name, const char *sig);
功能:返回类或接口实例(非静态)方法的方法 ID。方法可在某个 clazz 的超类中定义,也可从 clazz继承。该方法由其名称
和签名决定。 GetMethodID()可使未初始化的类初始化。要获得构造函数的方法 ID,应将 <init>作为方法名,同时将
void (V)作为返回类型。
参数: env:JNI接口指针。
clazz:Java类对象。
name:方法名。
sig:方法的签名。
返回值: 方法 ID,如果找不到指定的方法,则为 NULL。
抛出: NoSuchMethodError:如果找不到指定方法。
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败。
OutOfMemoryError:如果系统内存不足。
Call<type>Method例程 、Call<type>MethodA例程 、Call<type>MethodV例程
NativeType Call<type>Method (JNIEnv*en v, jobject obj , jmethodIDmethodID, ...); //参数附加在函数后面,
NativeType Call<type>MethodA (JNIEnv *env, jobject obj, jmethodID methodID,jvalue *args); //参数以指针形式附加
NativeType Call<type>MethodV (JNIEnv *env, jobject obj,jmethodID methodID, va_listargs); //参数以"链表"形式附加
说明:这三个操作的方法用于从本地方法调用Java实例方法。它们的差别仅在于向其所调用的方法传递参数时所用的机制。
这三个操作将根据所指定的方法 ID调用 Java 对象的实例(非静态)方法。参数 methodID必须通过调用 GetMethodID()
来获得。当这些函数用于调用私有方法和构造函数时,方法 ID必须从obj 的真实类派生而来,而不应从其某个超类派生。
当然,附加参数可以为空。
参数: env:JNI接口指针。
obj:Java对象。
methodID:方法 ID。
返回值: 返回调用 Java方法的结果。
抛出: 执行 Java方法时抛出的异常。
下表根据结果类型说明了各个方法类型。用户应将Call<type>Method中的 type 替换为所调用方法的Java 类型(或使用表
中的实际方法名),同时将 NativeType替换为该方法相应的本地类型。省略掉了其他两种类型。
Java层返回值 方法族 本地返回类型NativeType
返回值为void: CallVoidMethod() A / V (无)
返回值为引用类型: CallObjectMethod( ) jobect
返回值为boolean: CallBooleanMethod ( ) jboolean
返回值为byte: CallByteMethod( ) jbyte
返回值char : CallCharMethod( ) jchar
返回值short CallShortMethod() jshort
返回值为int : CallIntMethod() jint
返回值为long: CallLongMethod() jlong
返回值为float: CallFloatMethod() jfloat
返回值为double: CallDoubleMethod() jdouble
4、调用静态方法:也存在如下方法群,
jfieldID GetStaticMethodID (JNIEnv *env,jclass clazz, const char *name, const char*sig);
NativeType Call<type>Method (JNIEnv*env,jclass classzz , jfieldIDfieldID);
实例如下:
Java 的类如下:
/***test class 需要测试的jni里访问的类********/
public class testTime{
public int mVersion;
private int year;
private int month;
private int day;
private int hour;
private int minute;
private int second;
private int reserved;
public
byte[] channelCdata = new byte[1024];
public testTime()
{
}
public
void setTdtDate(int mYear, int mMonth, int mDay)
{
this.year = mYear;
this.month = mMonth;
this.day = mDay;
}
public
void setTdtTime(int mHour, int mMinute, int mSecond)
{
this.hour = mHour;
this.minute = mMinute;
this.second = mSecond;
}
public
void SetCharArray(byte[] cData, int data_size)
{
if (data_size == 0) {
return;
}
byte[] buffer = new byte[data_size];
System.arraycopy(cData, 0, buffer, 0, data_size);
String charText= new String(buffer);
}
public
byte[] getCharArray()
{
String myNane = "gchen"
byte[] charArray = myNane.getBytes();
return charArray;
}
}
/***************jni java class***********************/
package android.com.test;
public class jniTest{
public
native final int jni2JavaClass(Object objTestTime);
static
{
Log.i(TAG, "load testjni lib");
System.loadLibrary("testjni");
}
public jniTest()
{
}
public testJniCallJava()
{
testTime mtim = newtestTime();
jni2JavaClass((Object)mtim);
}
}
/***************jni cpp***********************/
static const char *classPathName = "android/com/test/jniTest";
static JNINativeMethod methods[] = {
{ "jni2JavaClass", "(Ljava/lang/Object;)I", (void *)android_com_test_jniTest_jni2JavaClass},
};
int android_com_test_jniTest_jni2JavaClassJNIEnv *env, jobject thiz,jobjectobjTestTime)
{
int ret = -1;
jclass testTime= env->GetObjectClass(objTestTime); /********获取Java的类引用*********/
if (testTime== NULL) {
return ret;
}
jfieldID mfield = env->GetFieldID(testTime, "mVersion", "I");/**********获取Java的成员以及类型**************/
int version = env->GetIntField(objTestTime,mfield);/**********访问Java的成员,读取**************/
env->SetIntField(objTestTime,(jin)0x00) ;;/**********访问Java的成员,设置**************/
jmethodID mMethodld == env->GetMethodID(testTime, "setTdtDate", "(III)V"); /**********获取Java的方法以及类型**************/
env->CallVoidMethod(objTestTime,mMethodld, 2016, 01,01); /**********调用Java的方法**************/
mMethodld== env->GetMethodID(testTime, "setTdtTime", "(III)V");
env->CallVoidMethod(objTestTime,mMethodld, 9, 30,30);
char mycontry[20] = "China"
jbyteArray byteArray;
jint cDataSize = strlen(mycontry);
byteArray = env->NewByteArray(cDataSize);
env->SetByteArrayRegion(byteArray, (jsize)0, (jsize)cDataSize, (jbyte *)mycontry);
mMethodld = env->GetMethodID(testTime, "SetCharArray", "([BI)V");/**********获取Java的方法以及类型**************/
env->CallVoidMethod(objTestTime, mMethodld,byteArray, cDataSize); /**********访问Java的方法**************/
env->DeleteLocalRef(byteArray);
char myname[20] = "";
mMethodld = env->GetMethodID(testTime, "getCharArray", "()[B"); /**********获取Java的方法以及类型**************/
byteArray = (jbyteArray)env->CallObjectMethod(objTestTime, mMethodld);/**********访问Java的方法**************/
jsize arrayLen = env->GetArrayLength(byteArray);
if (arrayLen > 0) {
env->GetByteArrayRegion(byteArray, (jsize)0, (jsize)arrayLen, (jbyte *)myname);
}
env->DeleteLocalRef(byteArray);
byte data[1024];
mfield = env->GetFieldID(testTime, "channelCdata", "[B"); /**********获取Java的成员以及类型**************/
jbyteArray chCdata = (jbyteArray)env->GetObjectField(objTestTime, mfield);
env->GetByteArrayRegion(chCdata, (jsize)0, (jsize)1024, (jbyte *)data);
env->SetByteArrayRegion(chCdata, (jsize)0, (jsize)1024, (jbyte *)data);/**********访问Java的成员,设置**************/
}