window上利用JNI在本地代码访问java代码
window下利用JNI在本地代码访问java代码
结果如下:
这一篇讨论在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; }
结果如下: