您的位置:首页 > 编程语言 > C语言/C++

Jni之在c++中调用java代码

2015-09-17 18:58 246 查看
第一步:完成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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: