JNI编程初试

新浪微博 QQ空间

首先编写Java类,用于调用C++库导出的方法:

public class TestMain
{
public native boolean printInfo();

public native int getNum();

public native void setNum(int num);
 

三个方法,第一个方法用于打印“hello world!”到屏幕。第二个方法用于获取一个全局变量的值,第三个方法用于设置全局变量的值。

找到eclipse输出的class文件的所在的包的位置,我的目录是在“F:\java_code\TestJNI\bin”,然后执行如下命令:

F:\java_code\TestJNI\bin>javah com.jni.test.TestMain

这样会在bin目录下生成一个“com_jni_test_TestMain.h”文件。

新建VC++动态链接库工程,在工程的包含目录中新增jvm的头文件。如下图所示:

image 
添加.cpp文件,编写三个函数的实现:

#include "com_jni_test_TestMain.h"

static int g_num = 0;

jboolean JNICALL Java_com_jni_test_TestMain_printInfo(JNIEnv *, jobject)
{
printf("hello world!\n");
return true;
}

jint JNICALL Java_com_jni_test_TestMain_getNum(JNIEnv *, jobject)
{

return g_num;
}


void JNICALL Java_com_jni_test_TestMain_setNum(JNIEnv *, jobject, jint num)
{
g_num = num;
}

使用VC环境编译出dll库文件。

使用如下三种方法加载动态库文件:

1)使用绝对路径

将TestJNI.dll库文件放置在F:\java_code\TestJNI\bin\目录下。获取该文件的绝对路径来加载:

private static void loadlibrary()

{

    System.load(System.getProperty("user.dir") + File.separator + "bin" + File.separator + "TestJNI.dll");

}

2)将动态库文件放在F:\java_code\TestJNI\bin\com包内的任意地方,将该库文件当作资源文件,首先将其复制到当前的class文件相同的目录下,然后调用加载:

System.loadLibrary("TestMain");

该方法需要复制一份库文件:

private static void loadlibrary2() throws UnsatisfiedLinkError
{
try
{
String libpath = System.getProperty("java.library.path");
if (libpath == null || libpath.length() == 0)
{
throw new RuntimeException("java.library.path is null");
}
String path = null;
StringTokenizer st = new StringTokenizer(libpath, System.getProperty("path.separator"));
if (st.hasMoreElements())
{
path = st.nextToken();
}
else
{
throw new RuntimeException("can not split library path:" + libpath);
}
Class<TestMain> thisClass = TestMain.class;
InputStream inputStream = thisClass.getResource("TestJNI.dll").openStream();
File dllFile = new File(new File(path), "TestMain.dll");
if (!dllFile.exists())
{
FileOutputStream outputStream = new FileOutputStream(dllFile);
byte[] array = new byte[8192];
for (int i = inputStream.read(array); i != -1; i = inputStream.read(array))
{
outputStream.write(array, 0, i);
}
outputStream.close();
}
System.loadLibrary("TestMain");
}
catch (UnsatisfiedLinkError e)
{
throw e;
}
catch (Throwable e)
{
throw new RuntimeException("load RegistryUtil.dll error!", e);
}
}

3)该方法理论上可行,但由于JVM的环境变量更改不能生效,导致无法加载。

private static void loadlibrary3()
{
URL classURL = TestMain.class.getResource("TestMain.class");
String classPath = new File(classURL.getPath()).getParent();
String syslibpath = System.getProperty("java.library.path") + classPath + ";";
System.setProperty("java.library.path", syslibpath);
for(String path: System.getProperty("java.library.path").split(";"))
{
System.out.println(path);
}
System.loadLibrary("TestJNI");
}

最后,编写Java调用native方法的主函数:

public static void main(String[] args)
{
TestMain handle = new TestMain();
handle.printInfo();
handle.setNum(10000);
System.out.println(handle.getNum());
}

输出结果为:

10000

hello world!

奇怪的是,handle.printInfo();调用的结果还晚于System.out.println(handle.getNum());输出在屏幕上面。查了一些资料,愿因在于windows使用的是全缓冲而非行缓冲,只有触发刷新缓冲时才会将内容输出。因此\n是不起作用的。

新浪微博 QQ空间

| 1 分2 分3 分4 分5 分 (5.00- 6票) Loading ... Loading ... | 这篇文章归档在:Java, JNI技术. | 永久链接:链接 | 评论(0) |

评论

邮箱地址不会被泄露, 标记为 * 的项目必填。

8 - 2 = *



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <img alt="" src="" class=""> <pre class=""> <q cite=""> <s> <strike> <strong>

返回顶部