1. 程式人生 > >JNI 和 JNA,java和其他語言的互調

JNI 和 JNA,java和其他語言的互調

僅工作中使用到,現查現用,理解不到位,請持懷疑態度檢視本文。如有問題請聯絡郵件:[email protected]; 以便交流。


java呼叫C語言的方法:

1、JNI --- java native interface
2、JNA
3、runtime.exec() ,沒有研究
4、CORBA , 沒有研究

JNI和JNA是什麼東西?

JNI是java和其他語言相互呼叫的機制,c 或者 c++寫的庫,java想使用,需要呼叫dll庫,這就使用JNI或者JNA去封裝庫提供的API。JNA是JNI的更高封裝,JNA使用很方便,JNI使用就相對麻煩,需要把dll中的每個API封裝一次,封裝的函式去呼叫dll中的API。JNA則直接宣告一下dll中的API,對應工作JNA都做了,我理解就是JNI的封裝本來是自己寫,但是JNA都幫你做了,所有使用起來JNA方便。

深入理解,以後在研究。


為什麼要用這個?

工作中需要用java呼叫c的dll完成一些工作。瞭解一些,java中框架也是用JNI封裝c或者c++的庫。因為底層用c或者c++實現效率高,而java應用程式的開發,框架的開發只是更多去關注邏輯的實現,不在需要自己實現類,而是學會如何使用已有的類。c和c++的工作者去想如何實現比如網路通訊,等等。


1、JNI 

      JNI是Java SDK中的一部分。

      JNI程式設計步驟:

      參考網址: 

http://www.cnblogs.com/moon1992/p/5260226.html

      1、java程式碼

package com.eclipse.example;  

public class JNITest {  
    public static void main(String[] args){
		System.loadLibrary("jniTest");  
        NativeMethod nm = new NativeMethod();  
          
        int ret = nm.jniFuncTest("hello world");  
        System.out.println(ret);  
          
    }  
  
}  
  
class NativeMethod {  
    /* native 原生態方法宣告  */  
    /** 
     * 函式名稱: int jniFuncTest(String string) 
     *  返回值: 無 
     *   描述:  指定目錄載入skyeye模組。載入模組之後才能獲取裝置類的資訊。 
     */  
    public native int jniFuncTest(String string);   
    // native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前檔案,而是在用其他語言(如C和C++)實現的檔案中。  
}
      用javac命令 或者 eclipse編譯程式碼,生成NativeMethod.class  和 JNITest.class 中間位元組碼檔案,也是java跨平臺的原因。

      用javah命令生成標頭檔案,標頭檔案裡是宣告的函式就是你自己需要在c中實現的函式,也就是需要封裝dll庫中的函式。

javah -classpath /d/workspace_eclipse/testjava/bin  -jni  com.eclipse.example.NativeMethod

     生成標頭檔案:com_eclipse_example_NativeMethod.h。標頭檔案:

/* DO NOT EDIT THIS FILE - it is machine generated */  
#include <jni.h>  
/* Header for class com_eclipse_example_NativeMethod */  
  
#ifndef _Included_com_eclipse_example_NativeMethod  
#define _Included_com_eclipse_example_NativeMethod  
#ifdef __cplusplus  
extern "C" {  
#endif  
/* 
 * Class:     com_eclipse_example_NativeMethod 
 * Method:    jniFuncTest 
 * Signature: (Ljava/lang/String;)I 
 */  
JNIEXPORT jint JNICALL Java_com_eclipse_example_NativeMethod_jniFuncTest  
  (JNIEnv *, jobject, jstring);   //c需要實現的函式。  
  
#ifdef __cplusplus  
}  
#endif  
#endif

      vs建立一個dll工程,參考地址:http://blog.csdn.net/bejustice/article/details/38294253

com_eclipse_example_NativeMethod.h 檔案:

/* DO NOT EDIT THIS FILE - it is machine generated */  
#include "jni.h"  
/* Header for class com_eclipse_example_NativeMethod */  
  
#ifndef _Included_com_eclipse_example_NativeMethod  
#define _Included_com_eclipse_example_NativeMethod  
#ifdef __cplusplus  
extern "C" {  
#endif  
/* 
 * Class:     com_eclipse_example_NativeMethod 
 * Method:    jniFuncTest 
 * Signature: (Ljava/lang/String;)I 
 */  
JNIEXPORT jint JNICALL Java_com_eclipse_example_NativeMethod_jniFuncTest  
  (JNIEnv *, jobject, jstring);   //c需要實現的函式。  
  
#ifdef __cplusplus  
}  
#endif  
#endif

com_eclipse_example_NativeMethod.c 檔案:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <Windows.h>
#include <direct.h>
#include <tchar.h>
#include "com_eclipse_example_NativeMethod.h"

/* 函式指標 */
typedef int (*FUNC)(char *);

static HMODULE hdll = NULL;

JNIEXPORT jint JNICALL Java_com_eclipse_example_NativeMethod_jniFuncTest
	(JNIEnv * env, jobject obj, jstring str){
		hdll = LoadLibraryEx(_T("C:\\cTest.dll"), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
		if (NULL != hdll)
		{
			FUNC func = (FUNC)GetProcAddress(hdll, "func");
			if (NULL != func)
			{
				return func(str);
			}
		}

		return 0;
}

       編譯,生成庫jniTest.dll。也就是再一次封裝了一個庫給java使用。確實有點麻煩了。
       這裡的麻煩在:c的型別需要和jni提供的型別對上,基本型別還好,但是複雜型別,就比較棘手。
       生成的jniTest.dll給Java呼叫使用。


2、JNA

     JNA是JNI更高的封裝,如何封裝不清楚。

      程式碼:

package com.eclipse.example;

import com.sun.jna.Library;
import com.sun.jna.Native;

interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary)Native.loadLibrary("cTest", CLibrary.class);
    
	int func(String str);   //型別,函式名,引數完全一致,宣告一下c 的dll庫中API就可以
}

java呼叫:

package com.eclipse.example;

public class JNITest {
	public static void main(String[] args){
		CLibrary.INSTANCE.func("hello");
	}
}


一些補充:
Lib dll h三者的關係:
h是宣告函式
dll是實現函式,執行時需要連線的
lib是橋樑,指明h中的函式在哪個dll中, 以及函式在dll的什麼位置。lib是連結時需要使用的。
vs中使用第三方庫的時候,屬性 --> 附加依賴項是.lib,不是.dll.
如果只是編譯連結程式,那麼h和lib就夠用了,執行只需要dll就可以了。
http://blog.csdn.net/paddybear/article/details/44058045

Java命名規則
http://www.cnblogs.com/wengfumin/articles/2337095.html

javah命令
http://www.cnblogs.com/kissazi2/p/3298884.html

elipse匯入dll
http://bbs.csdn.net/topics/390650733