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;

}


结果如下:

window上利用JNI在本地代码访问java代码