java jni调用过程分析
1.定义java类中的native方法,新建下面一个类
public class NativeDemo { public static native void say(); //static的native方法 public native void sayHello(); //实例的native方法,两者的处理不一样 public static int number = 10; int a = 2; public void callThis(){ System.out.println("c++ call java method"); } public static void main(String[] args) { System.loadLibrary("NativeJni"); // NativeDemo.sayHello(); new NativeDemo().sayHello(); say(); } }
2.进入java命令行
D:\project\workplatform.apps.demoLearnCenter\src\main\java>javah -help
用法:javah [选项] <类> 其中 [选项] 包括: -help 输出此帮助消息并退出 -classpath <路径> 用于装入类的路径 -bootclasspath <路径> 用于装入引导类的路径 -d <目录> 输出目录 -o <文件> 输出文件(只能使用 -d 或 -o 中的一个) -jni 生成 JNI样式的头文件(默认) -version 输出版本信息 -verbose 启用详细输出 -force 始终写入输出文件 使用全限定名称指定 <类>(例 如,java.lang.Object)。 D:\project\workplatform.apps.demoLearnCenter\src\main\java>javap -help Usage: javap <options> <classes>... where options include: -c Disassemble the code -classpath <pathlist> Specify where to find user class files -extdirs <dirs> Override location of installed extensions -help Print this usage message -J<flag> Pass <flag> directly to the runtime system -l Print line number and local variable tables -public Show only public classes and members -protected Show protected/public classes and members -package Show package/protected/public classes and members (default) -private Show all classes and members -s Print internal type signatures -bootclasspath <pathlist> Override location of class files loaded by the bootstrap class loader -verbose Print stack size, number of locals and args for methods If verifying, print reasons for failure
3.在vc++新建一个dll的控制台工程
4.在vc的工程里面导入刚才的那个NativeDemo.h的头文件,然后因为这个头文件需要引用jdk安装目录下的jni.h和jni_mt.h的两个头文件,从jdk的安装目录下的拷贝到工程里面
4.编写NativeDemo.h的头文件定义的两个类的实现(这里需要吧jni.h include的时候要改为“”,而不是<>,因为jni.h是在当前工程里面)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h" /* Header for class NativeDemo */ #ifndef _Included_NativeDemo #define _Included_NativeDemo #ifdef __cplusplus extern "C" { #endif /* * Class: NativeDemo * Method: say * Signature: ()V */ JNIEXPORT void JNICALL Java_NativeDemo_say (JNIEnv *, jclass); /* * Class: NativeDemo * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_NativeDemo_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
c++源文件
#include "NativeDemo.h"
#include "jni.h" #include <iostream> using namespace std; JNIEXPORT void JNICALL Java_NativeDemo_say(JNIEnv * env, jclass jclazz) //static的方法生成的两个参数是JNIEnv * env, jclass jclazz,第二个参数代表java的类的class实例 { jclass jclass_native = env->FindClass("NativeDemo"); //查找类的class对象, jfieldID jfield_numberId = env->GetStaticFieldID(jclass_native,"number", "I"); //获得jclazz类的静态字段number,第三个参数代表静态变量的签名,java每种类型对应到一个签名串 jint jfield_number = env->GetStaticIntField(jclass_native, jfield_numberId);//获得jclazz类的静态变量的值 cout << jfield_number << endl; //打印静态变量的值 } JNIEXPORT void JNICALL Java_NativeDemo_sayHello(JNIEnv *env, jobject jobj)//实例方法生成的第二个参数是jobject,代表某一个实例 { jclass clazz = env->GetObjectClass(jobj); //获得实例jobj的class对象 jfieldID jfield_numberId = env->GetFieldID(clazz,"a", "I"); //获得这个实例的a实例变量 jint jfield_value = env->GetIntField(jobj,jfield_numberId); //获得这个实例的a实例变量的值 cout << jfield_value << endl;//打印这个实例的a实例变量的值 }
5.编译这个vc的工程,生成一个dll文件
6.在我的电脑属性里面设置环境变量path增加这个dll的目录,因为java需要从path变量找到这个dll的目录
7.打开eclipse,编写调用的main函数代码
public class NativeDemo { public static native void say(); //static的native方法 public native void sayHello(); //实例的native方法,两者的处理不一样 public static int number = 10; int a = 2; public void callThis(){ System.out.println("c++ call java method"); } public static void main(String[] args) { System.loadLibrary("NativeJni"); // NativeDemo.sayHello(); new NativeDemo().sayHello(); say(); } }
执行这个main函数,结果如下
在java中需要使用System.loadLibrary("NativeJni");加载vc工程生成的dll文件,这里dll后缀不能加。