JNI 是 Java Native Interface 的縮寫。 Java™ 本機接口(Java Native Interface,JNI)是一個標準的 Java API,它支持將 Java 代碼與使用其餘編程語言編寫的代碼相集成。若是您但願利用已有的代碼資源,那麼可使用 JNI 做爲您工具包中的關鍵組件 —— 好比在面向服務架構(SOA)和基於雲的系統中。java
一、在JDK目錄下的javah.exe就是能夠將Java代碼轉化成C++代碼的頭文件。(注意完整類名與文件路徑)ios
二、將生成的頭文件複製到C++工程下,(注意:JDK目錄下的include頭文件也須要相應的包含到工程裏面), 按照生成的函數聲明來寫函數實現就能夠了。在cpp文件中要include這個文件。c++
#include <jni.h>這種是在系統目錄下去找,本身複製進去的須要改爲雙引號#include "jni.h"。編程
三、編譯好工程以後,就會生成dll文件了。(dll文件和exe同樣, 是可執行的二進制代碼)windows
四、生成dll後,就將其加到環境變量,方便調用。如在Java中System.loadLibrary("aaa")可調用aaa.dll架構
Eclipse在每次啓動的時候會讀取一次環境變量,更改環境變量以後須要重啓eclipse。app
Java中類型與C/C++中對應關係eclipse
![](http://static.javashuo.com/static/loading.gif)
Java中的類的對應編程語言
![](http://static.javashuo.com/static/loading.gif)
Sign簽名, 用來識別對應各個方法。函數
JDK下的javap.exe能輸出簽名。用法javap -s -p 完整類名
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
全局引用/局部引用/弱全局引用:
弱全局引用不會阻止垃圾回收器回收這個引用所指的對象。所以弱全局引用所引用的對象不必定存在。因此有必要先判斷。
Java中多態與C++中的Virtual對應關係(父類與子類的調用):
Java中類的成員方法都是虛擬的。CallNonvirtualVoidMethod()方法來調用。
一個簡單的例子:
Java端代碼:
[java] view plain copy
- package com.jni;
-
- import java.util.Date;
-
- /*
- * 2. 本地代碼C++訪問Java中的類與方法等. 在dll中改變了property的值, 調用了他的方法.
- */
- public class NativeAccessJava
- {
- //本地方法聲明
- public native void nativeAccessJavaMethod();
-
- //Java中的屬性
- public int property=10;
-
- //Java中的方法
- public int function(int a, Date date, int[] b)
- {
- System.out.println("Native C code access Java Class!");
- return 0;
- }
-
- //在C代碼中調用這個方法
- public double maxValue(double a,double b)
- {
- return a>b?a:b;
- }
-
- //關於多態與C++中virtual函數的對應
- public Father inst = new Son();
-
-
- public static void main(String[] args)
- {
- NativeAccessJava nativeAccessJava = new NativeAccessJava();
- System.out.println("改變前的值是: "+nativeAccessJava.property);
-
- System.setProperty("java.library.path", ".");//這裏就是在改臨時環境變量
- System.loadLibrary("NativeAccessObject");//NativeAccessObject.dll, 爲了方便, 能夠將動態連接庫直接設置到環境變量裏面
-
- //改變值的函數是在nativeAccessJavaMethod()中寫着的, 因此要先嗲用這個方法以後, 值才改變的
- nativeAccessJava.nativeAccessJavaMethod();
- System.out.println("改變後的值是: "+nativeAccessJava.property);
- }
- }
C++端代碼:
[cpp] view plain copy
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include "jni.h"
- /* Header for class com_jni_NativeAccessJava */
-
- #ifndef _Included_com_jni_NativeAccessJava
- #define _Included_com_jni_NativeAccessJava
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: com_jni_NativeAccessJava
- * Method: nativeAccessJavaMethod
- * Signature: ()V
- */
- JNIEXPORT void JNICALL Java_com_jni_NativeAccessJava_nativeAccessJavaMethod
- (JNIEnv *, jobject);
-
- #ifdef __cplusplus
- }
- #endif
- #endif
[cpp] view plain copy
- #include "com_jni_NativeAccessJava.h"
- #include "windows.h"
- #include <iostream>
- #include <algorithm>
- using namespace std;
-
- /************************************************************************/
- /* 2. 本地C代碼調用Java中的類. */
- /************************************************************************/
- JNIEXPORT void JNICALL Java_com_jni_NativeAccessJava_nativeAccessJavaMethod(JNIEnv *env, jobject obj)
- {
- jclass java_class = env->GetObjectClass(obj);//get class object
- jfieldID fieldID_prop = env->GetFieldID(java_class,"property","I");//get property id
- jmethodID methodID_func = env->GetMethodID(java_class,"function","(ILjava/util/Date;[I)I");//get method id e.g.
-
- //取得Java類中屬性property的值
- jint number = env->GetIntField(obj,fieldID_prop);
- cout << number<<endl; //輸出取得的值, 並輸出. 這個在Java調用的時候會輸出.
-
- //修改property的值, 改成120
- env->SetIntField(obj,fieldID_prop,120L);
-
- //調用java中的方法
- jmethodID methodID_max = env->GetMethodID(java_class,"maxValue","(DD)D");//get method ID
- jdouble maxValue = env->CallDoubleMethod(obj,methodID_max,3.11,3.15);
- cout<< "the maxValue is "<<maxValue<<endl;
-
- //調用java繼承關係的類, 調用的是子類的func方法. 至關於Father p = nativeAccessJava.p; p.func();
- jfieldID id_inst = env->GetFieldID(java_class,"inst","Lcom/jni/Father;");
- jobject inst = env->GetObjectField(obj,id_inst);//get Father class obj
-
- jclass class_Father = env->FindClass("com/jni/Father");//get Father class
- jmethodID id_Father_func = env->GetMethodID(class_Father,"func","()V");
-
- cout<<"------------默認是virtual, CallVoidMethod-------------"<<endl;
- env->CallVoidMethod(inst,id_Father_func); //調用子類的方法
- cout<<"------------CallNonvirtualVoidMethod-------------"<<endl;
- env->CallNonvirtualVoidMethod(inst,class_Father,id_Father_func);//調用父類的方法
-
- }
注意:
Java中的int對於C++中的long型,所以要寫成100L的形式。
Java中的字符是unicode,佔用2個字節,而c++中站一個字節,須要擴寬,所以char就要變成L‘3’型。
關於一些變量的聲明等信息,全在jni.h頭文件中尋找就好了。
使用JNI的兩個弊端:
( 1)、使用JNI後JAVA程序就不能跨平臺了.
(2)、Java是強類型的語言,而C++不是,寫JNI時必須很是當心。
強類型語言 :
首先咱們要聲明Java 語言強類型語言的重要性。首先,每一個變量有類型,每一個表達式有類型,並且每種類型是嚴格定義的。其次,全部的數值傳遞,不論是直接的仍是經過方法調用經由參數傳過去的都要先進行類型相容性的檢查。有些語言沒有自動強迫進行數據類型相容性的檢查或對衝突的類型進行轉換的機制。Java 編譯器對全部的表達式和參數都要進行類型相容性的檢查以保證類型是兼容的。任何類型的不匹配都是錯誤的,在編譯器完成編譯之前,錯誤必須被改正。 若是你有C或C++的背景,必定要記住Java對數據類型兼容性的要求比任何語言都要嚴格。例如,在C/C++ 中你能把浮點型值賦給一個整數。在Java 中則不能。另外,C語言中,在一個參數和一個自變量之間沒有必然的強制的類型檢查。在Java 中則有。起初你可能發現Java 的強制類型檢查有點繁煩。可是要記住,從長遠來講它將幫助你減小程序出錯的可能性。