这一篇讨论在c/c++代码里生成java对象,访问修改其字段、调用其方法。编译和运行流程参见上一篇。
这里写两个java类:JniFuncMain和JniTest。
1.在JniFuncMain是主类。里面有一个静态整形字段。
2.仍然按照常规流程用static block加载dll库。
3.而且还声明了一个本地方法--注意static属性。返回一个JniTest对象。对象的构造过程在createJniObject()的本地函数调用java构造方法执行。
public class JniFuncMain
{
private static int staticIntField = 200;
// 加载本地库jnifunc.dll
static{ System.loadLibrary("jnifunc");}
public static native JniTest createJniObject();
public static void main(String[] args)
{
System.out.println("[java]: createJniObject() call native method!");
JniTest jniObj = createJniObject();
jniObj.callTest();
}
}
class JniTest
{
private int intField;
// 构造方法
public JniTest( int num )
{
intField = num;
System.out.println("[java]:JniTest' constructor been called! init intField =" + num);
}
// 此方法由本地代码调用
public int callByNative(int num)
{
System.out.println("[java]: i be called by native code! set intField = " + num);
return num;
}
public void callTest()
{
System.out.println("i be called by java code!");
return;
}
}
本地c++代码实现createJniObject函数:
#include "JniFuncMain.h" // 注意用javah命令生成
#include <stdio.h>
JNIEXPORT jobject JNICALL Java_JniFuncMain_createJniObject(JNIEnv *env, jclass clazz)
{
jclass targetClass;
jmethodID mid;
jobject newObject;
jstring helloStr;
jfieldID fid;
jint staticIntField;
jint result;
// 获得JniFuncMain类的staticIntField变量值
fid = env->GetStaticFieldID(clazz, "staticIntField", "I");
staticIntField = env->GetStaticIntField(clazz, fid);
printf("[cpp]get JniFuncMain private field staticIntField value\n");
printf(" JniFuncMain.staticIntField = %d\n", staticIntField);
// 查找要访问的成员所在的类
targetClass = env->FindClass("JniTest");
// 查找构造方法
mid = env->GetMethodID(targetClass, "<init>", "(I)V");
// 1."(I)V"是用javap反编译工具反编译JniTest的成员
// 获得的签名。GetMethodID方法会根据此签名找到该方法。
// 反编译class文件命令,例子: javap -s -p 类名
// 2. 第一个参数不是JNIEnv*类型是因为此代码是c++代码。原理类似于this指针。
// 3. 只有获得构造方法时第2个参数是<init>,其他的,直接传入方法名称即可。
// 生成JniTest对象
printf("[cpp]JniTest object generate...\n");
newObject = env->NewObject(targetClass, mid, 100);
// 调用jniTest对象的方法返回一个值,本地打印出来
mid = env->GetMethodID(targetClass, "callByNative", "(I)I");
result = env->CallIntMethod(newObject, mid, 200);
// 再调用一下jni设置字段的方法
fid = env->GetFieldID(targetClass, "intField", "I");
printf("[cpp]:set JniTest object field intField = 200\n");
env->SetIntField(newObject, fid, 200);
return newObject;
}
结果如下: