JNI指的是“JAVA本地调用接口”。通过这种技术JAVA可以调用由其它语言(包括C++)为JAVA编写的本地代码。在Windows上这可能是DLL,在Linux上则可能是一个SO。
我的这个实验是在Windows上通过的,所以我所指的本地代码是一个DLL动态链接库。
一、实现JNI
1)先编写一个Main.java文件如下。
class Main{
public static native void hello();
public static void main(String args[])
{
System.load("C://T.DLL");
hello();
}
}
解释:其中以native修饰的hello函数就是一个本地调用接口,它没有函数体因为函数体在我将要生成的T.DLL中。main函数是Main类的入口首先它加载T.DLL然后调用其中的hello函数,就这么简单!
2)编译Main.java
命令:javac Main.java
解释:如果没有问题这时已生成了Main.class文件,对JAVA来讲这是一个编译后的可执行文件。
3)生成本地代码库————“T.DLL”
3.1) 生成C++头文件————“Main.h”
命令:javah Main
解释:如果没有问题这时已生成了“Main.h”文件,我生成的文件内容如下,注意其中对Java_Main_hello函数的声明,这就是JAVA中的helllo函数
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Main
* Method: hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Main_hello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
3.2)用VC生成一个DLL工程,我的主要程序文件如下,注意对Java_Main_hello函数的实现
// T.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#include "Main.h"
JNIEXPORT void JNICALL Java_Main_hello(JNIEnv *, jclass)
{
MessageBox(0,L"hello",L"你用过HL脚本语言吗?",MB_OK);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
3.3)编译C++工程生成T.DLL,并拷贝到C盘根目录下。
4)执行Main.class
命令:java Main
解释:如果没有问题这时已看到了弹出的MessageBox
二、卸载本地代码库
如果照上面那样当Main执行完了进程就退出了,自然T.DLL也就卸载了。但是实际的应用中会遇到进程还要继续而必须卸载T.DLL的时候。终于我在网上找到了这样的方法,拿来与大家分享!
1)修改Main类代码,新的Main.java文件内容如下,注意与开始时的不同之外(尤其注意unloadNativeLibs函数)
import java.util.*;
import java.lang.reflect.*;
class Main{
public static native void hello();
private void unloadNativeLibs() throws Throwable {
ClassLoader classLoader = this.getClass().getClassLoader();
Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
field.setAccessible(true);
Vector libs = (Vector) field.get(classLoader);
Iterator it=libs.iterator();
Object o;
while(it.hasNext())
{
o=it.next();
Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]);
finalize.setAccessible(true);
finalize.invoke(o, new Object[0]);
}
}
public boolean freeLibrary(){
boolean result=true;
try{
unloadNativeLibs();
}catch(Throwable e){
result=false;
}
return result;
}
public static void main(String args[])
{
System.load("C://T.DLL");
hello();
new Main().freeLibrary();
int i=0;
for(i=0;i<10000;i++)
{
System.gc();
}
}
}
解释:在main函数中当().freeLibrary调用之后,程序开始了一个长时间的循环,在这个循环进行的过程中进程没有退出,但我可以删除T.DLL了,这表示它已被卸载了。