具体如下:
JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。
简单介绍及应用如下:
一、JAVA中所需要做的工作
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:
static {
System.loadLibrary(“goodluck”)
}
在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。
还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:
public native static void set(int i)
public native static int get()
然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。
例如程序testdll.java,内容为:
public class testdll
{
static
{
System.loadLibrary("goodluck")
}
public native static int get()
public native static void set(int i)
public static void main(String[] args)
{
testdll test = new testdll()
test.set(10)
System.out.println(test.get())
}
}
用javac testdll.java编译它,会生成testdll.class。
再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。
二、C/C++中所需要做的工作
对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的腔历路径下面,就可以用JAVA调用C/C++所实现的功能了。
接上例子。我们先看一下testdll.h文件的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testdll */
#ifndef _Included_testdll
#define _Included_testdll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testdll
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_testdll_get
(JNIEnv *, jclass)
/*
* Class: testdll
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_testdll_set
(JNIEnv *, jclass, jint)
#ifdef __cplusplus
}
#endif
#endif
在具体实现的时候,我们只关心两个函数原型
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)
和
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint)
这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见卖羡,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。
好,下面我们用testdll.cpp文件具体实现伍配搜这两个函数:
#include "testdll.h"
int i = 0
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)
{
return i
}
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)
{
i = j
}
编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll
把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
1. “DLL的头文件”是个模糊概念,其实应该包含“DLL模块自己用的头文件”和“给DLL以外卜旁的模块用的头文件”,但一般地,通过条件编译开关,都把这两个文件合并在一起。
2. 给DLL以外的模块用的“DLL的头文件”中不启弊唤要“定义”全局变量,而应该“声明”全局变量。
3. DLL中用的全局变量应该在DLL模块内定义。(无论是DLL的cpp文件或在“DLL模块自己用的头文件”中)
下面给个例子。(例子中将“DLL模块自己用的头文件”和“给DLL以外的模块用的头文悄凯件”合并在一起)
A。DLL的cpp文件:(dlltest.cpp)
#define DLL_EXPORT //这是编译DLL模块本身 或编译其他使用者的开关
#include "dlltest.h"
long g_count = 0
int dllmul(int i, int j) { g_count++ return i*j}
B。DLL的头文件:(dlltest.h)
#ifndef DLL_TEST
#define DLL_TEST
#ifndef DLL_EXPORT
extern "C" __declspec(dllimport) int dllmul(int i, int j)
extern __declspec(dllimport) long g_count
#else
extern "C" __declspec(dllexport) int dllmul(int i, int j)
extern __declspec(dllexport) long g_count
#endif
#endif
C。使用上述DLL的程序
#include "dlltest.h"
#include "stdio.h"
int main(){
printf("The count is %d\n",g_count)
printf("5*6=%d\n",dllmul(5,6))
printf("The count is %d\n",g_count)
getchar()
return 0
}
最后提醒:如果有多个线程或进程使用你的DLL模块,注意共享变量和共享保护。可以看看Jetfrey Richter写的《Windows核心编程》
使用VC下的cl和link手工创建dll并实现函数导入1、创建dll头文件:
/*
* dllmain.h
*/
#ifndef _DLLMAIN_H
#define _DLLMAIN_H
int getNumber()
#endif
2、创建dll源文件:
/*
* dllmain.c
*/
#include "dllmain.h"
int getNumber()
{
return 10
}
3、 创建def文件:
export.def
LIBRARY MY_DLLMAIN MY_DLLMAIN 将成为生成的dll的名称
EXPORTS
getNumber @1 这个名称即为函数的实际导出名称 @1为函数的导出编州腊尺号
4、生成dll文件:
cl dllmain.c /c
link /def:export.def /dll dllmain.obj
这时,工程中已经包含了 dllmain.h dllmain.c export.def dllmain.obj dllmain.lib dllmain.exp MY_DLLMAIN.dll 其中,后4个文件是编译链接过程中生成的文件
5、创建dlltest.c:
/*
* dlltest.c
*/
#include <stdio.h>
#include "dllmain.h" //dll库的头文件
#pragma comment(lib,"dllmain.lib") //dllmain.lib即是上一步生成的文件
int main()
{
printf("%dn",getNumber())
}
6、册高编译、链接dlltest.c
cl dlltest.c /c
link dlltest.obj
注意:这里dllmain.lib和dllmain.h应该和dlltest.c在同一个目录中。此步的结果将生成 dlltest.exe
7、运行:
dlltest
这时,系统将载入my_dllmain.dll这个动态链接库,将调用其中的getNubmer函数局凳。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)