1. 程式人生 > >Java採用JNI呼叫VC++生成的dll(Java與C++互動)

Java採用JNI呼叫VC++生成的dll(Java與C++互動)

     應專案需求,需要android呼叫java,java再呼叫C++實現android一個圖片匹配的功能,我們作為java組需要和C++和Android進行互動。下面是java和C++採用JNI的方式進行介面傳參互動,我做的一個demo並執行成功。

什麼是JNI?

JNI全拼是Java Native Interface,中文意思為Java本地呼叫。JNI標準是Java平臺的一部分,它允許java和其他語言的程式碼進行互動。JNI開始是為了本地已經編譯好的語言,尤其是C和C++而設計的,我們也可以使用JNI和其他語言進行溝通,我們只要呼叫約定受支援了就可以了。

什麼原理?

我們知道C++中或者C#等.net都能生成.dll類庫,而C++(或.net)中生成的.dll檔案,相當於我們java程式中java原始碼通過編譯生成的.class檔案,我們在java程式中直接通過code呼叫C++的dll檔案即可。

在C語言中如果生成一個動態連結庫dll檔案的時候,需要兩部分,一部分是為.h的標頭檔案,這個檔案是負責對一些方法的宣告,而.cpp檔案負責對方法的實現。而在java中,在JDK安裝目錄的include包中有個jni.h和jni_md.h,這個可以說是java釋出的一個介面,在C++中可以直接使用這兩個head型別的檔案對java要呼叫的C++方法編譯,讓java呼叫,並可以接收java傳遞過來的引數。直接上程式碼啦。

具體的步驟如下所示(java釋出一個介面,讓C++實現乘法的功能)

1、建立java原始碼如下所示。

建立java project,在src下建立com包,在com包下面建立我們的java類Reliability.java,程式碼如下所示。

package com;
public class Reliability {
	static {
		try {
			System.loadLibrary("Reliability"); // call dll
		} catch (UnsatisfiedLinkError e) {
			System.out.println("The load problem");
		}

	}
	public native int shanfei(int i);
	public static void main(String[] args) {
		Reliability reliability = new Reliability();
		System.out.print(reliability.shanfei(6));
	}
}

2、編譯.java原始檔。

我們想實現傳遞int 整型引數來實現自己和自己相乘的結果,而實現shanfei(int p)方法的是C++。我們可以通過System.loadLibrary("Reliability")方法實現載入C++生成的dll,通過native宣告方法介面以及引數。

編寫好自己的Reliability.java程式碼後,可以使用MyEclipse編譯為Reliability.class檔案或者是直接用javac命令編譯為.class檔案。

我的使用的MyEclipse進行編譯的,會在/Reliability/bin/com資料夾中生成Reliability.class檔案。

3、用javah 命令讓Reliability.class檔案生成C++需要的.h檔案,也就是交給C++的介面。

在這裡需要注意的是,一定要轉到你編譯成class檔案的上一級目錄進行javah命令,並且你的JDK已經配置好環境變數,這裡的環境變數為JAVA_HOME:安裝jdk bin資料夾的上一級目錄,比如我的jdk安裝在C:\java\bin....,那我的JAVA_HOME為:C:\java 。path目錄:引用JAVA_HOME並且加上\bin ,為 %JAVA_HOME%\bin 。classpath為: .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;這是一定要配置好的。然後在dos視窗如下編寫如下命令,生成給C++ .h的檔案。


這樣在你的class檔案上一級目錄中就會出現.h 的檔案,並且引入到你的MyEclipse中,與com包同級。


4、這樣java已經給C++釋出好了com_Reliability.h的標頭檔案,C++要去實現這個方法了。

因為要生成dll檔案,所以我們需要建立動態連結庫檔案,如果用的是C++ 6.0環境,就是建立projects --Dynamic-LInk Library工程。

之後新增我們的com_Reliability.h檔案到我們的DLL專案中,目錄結構如下所示。


標頭檔案中的程式碼如下所示,com_Reliability.h。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_Reliability */

#ifndef _Included_com_Reliability
#define _Included_com_Reliability
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_Reliability
 * Method:    shanfei
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_Reliability_shanfei
  (JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

實現的Reliability.cpp程式碼如下所示。
#include<jni.h>
#include "com_Reliability.h"
#include<stdio.h>
#include<jni_md.h>

JNIEXPORT jint JNICALL Java_com_Reliability_shanfei(JNIEnv *, jclass, jint p)
{
	 int j = p*p;
	 return j;
		
}

切忌:.cpp中和.h中的方法名一定要相同!!!並且把從java中找到的jni.h 和jni_md.h貼上到外部依賴資料夾,或者直接放到VC98\include資料夾中。

5、生成dll檔案

這樣我們ctrl+F7編譯,F7在C++專案的debug中生成Reliability.dll檔案,這樣我們再把這個dll檔案放到java編譯的.class目錄,同時放到MyEclipse與src同級。這樣執行java的Reliability.java檔案,就看到C++給我們計算的結果了。顯示如下所示。


總結:

上述大致就是這個過程,在這個過程中會出現這樣或者那樣的問題,我也在不斷的去嘗試錯誤的所在,嘗試改動,最根本的就是計算機報錯了,就一定是自己哪個地方有錯誤,抱著這樣的心態,耐心的找答案、嘗試、思考,設定斷點除錯,看到底是哪步出現的錯誤,最終會解決問題,讓你興奮的看到執行結果。