There are two different ways to load a native library into a running Java program: System.loadLibrary(String) and System.load(String). The System.loadLibrary
method allows us to load a library from the "default" path. System.load
allows us to load a library from anywhere via its absolute path.
First, System.loadLibrary
. We'll use System.loadLibrary
for our example because most other examples use it, and because we're doing all of our work in one directory.
When using System.loadLibrary
, the only thing we specify is the name of the DLL file we want. The JVM will search for it in the "Java library path." This is a path which is given by the java.library.path
system property (and hence can be altered on the java.exe
command line using the -D
option). The default value of this appears to be related to the Windows path, though it appears to be somewhat scrambled, and I'm not quite sure how or why. In other words, I'm not sure how the Windows JVM creates the initial value of java.library.path
. This is the default on my system:
java.library.path=C:\WINNT\system32;.;C:\WINNT\System32;C:\WINNT;c:\applications\asc\pervasive\BIN;c:\cygwin\bin;
C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;\win32
C:\>echo %PATH%
c:\applications\asc\pervasive\BIN;c:\cygwin\bin;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;\win32
Note that the current directory is inserted into the
PATH
; I believe that this is something that Windows does by default. I am going to execute the program from the directory in which
HelloWorld.dll
was created, so I won't have to mess with
java.library.path
. One could also use command-line options to alter
java.library.path
or simply copy the DLL into one of the Windows directories.
In order to cause the JVM to load the library, we need to alter our Java code:
package example.jni;
public class HelloWorld {
private static native void writeHelloWorldToStdout();
public static void main(String[] args) {
System.loadLibrary("HelloWorld");
writeHelloWorldToStdout();
}
}
Go ahead and re-compile the Java program.
The JVM takes care of resolving "HelloWorld" to "HelloWorld.dll" (on UNIX, it would resolve it to "libHelloWorld.so").
Anyway, we're finished and can proceed to the next step.
If we were to use the System.load
method, we'd just insert code like:
System.load("c:/path/to/dll/HelloWorld.dll");
By the way, that's a good non-JNI tip -- the JVM accepts forward slashes just fine, even for Windows file names. Some of my programs (e.g., web programs which involve forward slashes in URLs) have been vastly simplified knowing that, not to mention the lack of annoying escape characters. (Disclaimer: As far as I know, this behavior isn't part of the Java specification, so it's possible it could be changed or operate differently in other VMs.)
===============================
java服务函数的dll实现,就是你用c或c++写的dll,这个文件要放在java.library.path,
而java.library.path里有许多路径,如c:\jdk142\bin,你可以打印出来看一下:
(System.out.println(System.getProperty("java.library.path"));
===============================
学习了一下JNI,发表文章的时候不知道该选什么好了,不知道JNI应该属于那个范畴^_^。
1.简介
JNI是Java Native Interface的缩写,它的设计目的是:
The standard Java class library may not support the platform-dependent features needed by your application.
You may already have a library or application written in another programming language and you wish to make it accessible to Java applications
You may want to implement a small portion of time-critical code in a lower-level programming language, such as assembly, and then have your Java application call these functions
2.JNI的书写步骤
编写带有native声明的方法的java类
使用javac命令编译所编写的java类
使用javah ?jni java类名生成扩展名为h的头文件
使用C/C++实现本地方法
将C/C++编写的文件生成动态连接库
ok
1) 编写java程序:
这里以HelloWorld为例。
代码1:
class HelloWorld {
public native void displayHelloWorld();
static {
System.loadLibrary("hello");
}
public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
}
声明native方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明改方法为native的,并且不能实现。其中方法的参数和返回值在后面讲述。
Load动态库:System.loadLibrary("hello");加载动态库(我们可以这样理解:我们的方法displayHelloWorld()没有实现,但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化)这里一般是以static块进行加载的。同时需要注意的是System.loadLibrary();的参数“hello”是动态库的名字。
main()方法
2) 编译没有什么好说的了
javac HelloWorld.java
3) 生成扩展名为h的头文件
javah ?jni HelloWorld
头文件的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: displayHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
(这里我们可以这样理解:这个h文件相当于我们在java里面的接口,这里声明了一个Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致)。
4) 编写本地方法
实现和由javah命令生成的头文件里面声明的方法名相同的方法。
代码2:
1 #include <jni.h>
2 #include "HelloWorld.h"
3 #include <stdio.h>
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
printf("Hello world!\n");
return;
}
注意代码2中的第1行,需要将jni.h(该文件可以在%JAVA_HOME%/include文件夹下面找到)文件引入,因为在程序中的JNIEnv、jobject等类型都是在该头文件中定义的;另外在第2行需要将HelloWorld.h头文件引入(我是这么理解的:相当于我们在编写java程序的时候,实现一个接口的话需要声明才可以,这里就是将HelloWorld.h头文件里面声明的方法加以实现。当然不一定是这样)。然后保存为HelloWorldImpl.c就ok了。
5) 生成动态库
这里以在Windows中为例,需要生成dll文件。在保存HelloWorldImpl.c文件夹下面,使用VC的编译器cl成。
cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll
注意:生成的dll文件名在选项-Fe后面配置,这里是hello,因为在HelloWorld.java文件中我们loadLibary的时候使用的名字是hello。当然这里修改之后那里也需要修改。另外需要将-I%java_home%\include -I%java_home%\include\win32参数加上,因为在第四步里面编写本地方法的时候引入了jni.h文件。
6) 运行程序
java HelloWorld就ok。^_^