第一步:完成java代码
public class JniMain {
private static int staticIntField=300;
static{
System.loadLibrary("JniFunc");
}
public static native JniTest createObject();
public static void main(String []args){
System.out.println("调用本地方法");
JniTest jniObject=createObject();//利用本地方法生成java对象
jniObject.callTest();
}
}
public class JniTest {
private int intField;
public JniTest(int num){
this.intField=num;
System.out.println("调用JNItest对象的构造方法:intField="+intField);
}
public int callByNative(int num){
System.out.println("jniTest对象的callByNative调用="+num);
return num;
}
public void callTest(){
System.out.println("callTest被调用="+intField);
}
}
第二步:利用javah命令生成c++头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_jni_JniMain */
#ifndef _Included_com_jni_JniMain
#define _Included_com_jni_JniMain
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jni_JniMain
* Method: createObject
* Signature: ()Lcom/jni/JniTest;
*/
JNIEXPORT jobject JNICALL Java_com_jni_JniMain_createObject
(JNIEnv *, jclass);//由于是static静态方法,所以传的参数为jclass类型
#ifdef __cplusplus
}
#endif
#endif
第三步:完成c++代码,要在vs中项目属性里的包含目录中添加jdk的相关c/c++文件的目录
#include "com_jni_JniMain.h"
#include<stdio.h>
JNIEXPORT jobject JNICALL Java_com_jni_JniMain_createObject(JNIEnv *env, jclass jclassParams){
jclass targetClass;
jmethodID mid;
jobject newObject;
jstring helloStr;
jfieldID fid;
jint staticIntField;
jint result;
//参数分别指的是包含静态成员的类,成员变量名,成员变量的签名(可以通过javap -s -p 类名命令来获取)
printf("本地方法开始!\n");
fid=env->GetStaticFieldID(jclassParams,"staticIntField","I");
//根据类及成员的字段ID来获取成员变量的值
staticIntField=env->GetStaticIntField(jclassParams,fid);
printf("获取JniFuncMain类的staticIntField值=%d\n",staticIntField);
//获取指定类名的jclass对象
targetClass=env->FindClass("com/jni/JniTest");//包名+类名
//查找指定的方法的methodID,根据jclass对象、方法名(构造函数的方法名为<init>)、方法签名
mid=env->GetMethodID(targetClass,"<init>","(I)V");
printf("生成JniTest对象\n");
//利用构造函数创建对象、最后为构造函数的参数
newObject=env->NewObject(targetClass,mid,100);
mid=env->GetMethodID(targetClass,"callByNative","(I)I");
result=env->CallIntMethod(newObject,mid,200);
fid=env->GetFieldID(targetClass,"intField","I");
//设定字段的值
env->SetIntField(newObject,fid,result);
return newObject;
}
从代码来看:要调用静态方法或静态成员变量:首先利用JNIEnv对象来查找到相应的类的jclass类型->然后在获取方法或成员ID,这里利用变量签名和方法签名->然后在利用jclass对象调用方法或对数据进行操作
而使用非静态方法则需要多一个查找并调用构造函数的过程
可以使用javap反编译命令来获取成员或方法签名,实现要先编译java文件
第四步:利用vs的命令提示工具生成dll共享库,利用其cl命令
第五步:执行得到结果
如果是纯c++调用jni则需要自己加载jvm,其余大致相同,不过需多加在一个lib库,如下所示
#include<jni.h>
int main(){
JNIEnv *env;
JavaVM *vm;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;
//设置java虚拟机选项
options[0].optionString="-Djava.class.path=.";
vm_args.version=0x00010008;//在jni.h文件中可找到该值
vm_args.options=options;
vm_args.nOptions=1;
vm_args.ignoreUnrecognized=JNI_TRUE;
//生成java虚拟机
res=JNI_CreateJavaVM(&vm,(void**)&env,&vm_args);
cls=env->FindClass("InvocationApiTest");
mid=env->GetStaticMethodID(cls,"main","([Ljava/lang/String;)V");
jstr=env->NewStringUTF("hello invocationApiTest!");
stringClass=env->FindClass("java/lang/String");//获取String类jclass实例
args=env->NewObjectArray(1,stringClass,jstr);//创建String数组
env->CallStaticVoidMethod(cls,mid,args);//调用main方法
vm->DestroyJavaVM();//关闭jvm
return 0;
}