天天看點

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
      
java jni調用過程分析

3.在vc++建立一個dll的控制台工程

java jni調用過程分析

4.在vc的工程裡面導入剛才的那個NativeDemo.h的頭檔案,然後因為這個頭檔案需要引用jdk安裝目錄下的jni.h和jni_mt.h的兩個頭檔案,從jdk的安裝目錄下的拷貝到工程裡面

java jni調用過程分析

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檔案

java jni調用過程分析

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 jni調用過程分析