购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 使用JNI

在密码学领域搞开发,无论是看密码算法的文献资料还是调用业界著名的密码函数库、大数库、数学库等,都免不了要和C语言打交道。为了避免重复造轮子或在关键领域需要提高性能,一些基础的算法功能,我们完全可以利用现有的C函数库来作为巨人的肩膀。这就涉及在Java中调用C函数的问题。Java提供了JNI机制,使得调用C函数易如反掌。

JNI(Java native interface,Java原生接口),是Java语言的本地编程接口。在Java程序中,我们可以通过JNI实现一些用Java语言不便实现的功能,具体如下:

(1)标准的Java类库没有提供应用程序所需要的功能,通常这些功能是平台相关的(只能由其他语言编写)。

(2)希望使用一些已经有的类库或者应用程序,而它们并非用Java语言编写的。

(3)程序的某些部分对速度要求比较苛刻,你选择用汇编或者C语言来实现并在Java语言中调用。

(4)为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,本地代码比字节码难以破解。

Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序或者Java无法处理的任务无疑是一个很好的方式。Java中的JNI开发流程主要分为以下6步:

(1)编写声明了native方法的Java类。

(2)将Java源代码编译成class字节码文件。

(3)用javah-jni命令生成.h头文件(javah是JDK自带的一个命令,-jni参数表示将class中用native声明的函数生成jni规则的函数)。

(4)用本地代码实现.h头文件中的函数。

(5)将本地代码编译成动态库(Windows:*.dll,Linux/Unix:*.so,Mac OS x:*.jnilib)。

(6)复制动态库至java.library.path本地库搜索目录下,并运行Java程序。

下面我们通过实例来说明。

【例2.5】 第一个JNI程序

(1)打开Eclipse,设置工作区路径,注意本例用编号作为工作区文件夹名(这是为了给大家演示多样性情况,所以本例没有用myws作为工作区名称)。新建一个Java工程,工程名是SimpleHello。在工程中新建一个类,在New Java Class对话框的Package文本框中输入包名“com.study.jni.demo.simple”,在Name文本框中输入类名“SimpleHello”,同时选中“public static void main(String []args]”复选框,如图2-45所示。

这里简单解释一下Package(包)。Java提供了包机制,用于区别类名的命名空间。包机制把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名以示区别。因此,包可以避免名字冲突。另外,包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。Java使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

图2-45

在图2-45中设置好3个选项后,单击Finish按钮关闭对话框。此时,Eclipse会显示SimpleHello.java的编辑窗口。我们在SimpleHello.java中输入如下代码:

main函数中调用了sayHello函数。注意,sayHello()方法的声明中有一个关键字native,表明这个方法使用Java以外的语言来实现。该方法不包括业务功能实现,因为我们要用C/C++语言实现它。同时System.loadLibrary("hello")这句代码是在静态初始化块中定义的,系统用来装载hello库,这就是我们在后面生成的hello.dll。

(2)生成.h文件。打开命令行窗口,然后进入SimpleHello.java所在的目录,这里是D:\eclipse-workspace\2.5\SimpleHello\src\com\study\jni\demo\simple\,然后输入如下命令:

    javac SimpleHello.java -h .

注意,-h后面有一个空格,然后是一个黑点。选项-h表示需要生成jni的头文件,黑点表示在当前目录下生成头文件。如果需要指定目录,那么可以把黑点改成文件夹名称(文件夹会自动新建)。执行该命令后,会在同一目录生成两个文件:SimpleHello.class和com_study_jni_demo_simple_SimpleHello.h。后者是我们所需的头文件,不要修改,后面在VC工程中会用到。

(3)编写本地实现代码。

用C/C++语言实现Java中定义的方法,其实就是新建一个dll程序。dll其实就是一个动态库。关于更多动态库的知识,大家可以参考清华大学出版社出版的《Visual C++ 2017从入门到精通》。

打开VC 2017,按Ctrl+Shift+N快捷键打开“新建项目”对话框,然后在左边选择“Windows桌面”项,在右边选择“Windows桌面向导”,然后在下面输入工程名“hello”,并设置好工程所存放的位置,如图2-46所示。

图2-46

单击“确定”按钮,随后会出现“Windows桌面项目”对话框,设置“应用程序类型”为“动态链接库(.dll)”,并取消勾选“预编译标头”复选框,如图2-47所示。

单击“确定”按钮,此时一个dll工程就建立起来了。在VC解决方案中双击hello.cpp,然后在编辑框中输入如下代码:

图2-47

代码主要实现了sayHello,里面的内容很简单,主要是把Java传来的参数打印出来。其中,jni.h是JDK的自带文件,我们需要为VC工程添加JDK路径包含,在VC菜单栏选择“项目→属性→配置属性→C/C++”,然后在右边“平台”下选择“x64”(因为我们要生成64位的dll),并在“附加包含目录”旁输入“%JAVA_HOME%\include;%JAVA_HOME%\include\win32”,如图2-48所示。

图2-48

单击“确定”按钮关闭对话框,然后把D:\eclipse-workspace\2.5\SimpleHello\src\com\study\jni\demo\simple\下的com_study_jni_demo_simple_SimpleHello.h复制到VC工程目录下,并在VC中添加该头文件,并在VC工具栏上选择解决方案平台为x64,如图2-49所示。

图2-49

在VC工具栏处切换解决方案平台为x64,按F7键生成解决方案,此时将在hello\x64\Debug下生成hello.dll,把该文件复制到C:\windows下。至此,VC本地代码开发工作完成。

(4)重新回到Eclipse中,按Ctrl+F11快捷键运行工程,可以看到下方控制台窗口上有输出内容,如图2-50所示。

图2-50

其中,打印了VC程序中的打印语句,还打印了VC函数的返回值(字符串:hello Ljy)。从这个例子,我们可以验证Java向本地函数传参数并获取返回值,这个操作成功了!如果不喜欢在C:\windows下添加文件,那么可以把hello.dll放到Java工程目录或者任意一个目录下,只要在Java中指定绝对路径即可,比如把hello.dll放到D盘下,则在Java程序要写成绝对路径: eprwHHVB5zM8Jp1LvZ4Q/iNNSlLiSLLhE3a2aPMLRFVfCBmdROO6vScg6ctAWL87

    //写绝对路径时,后缀名.dll也要写出来,并且要用load函数
    System.load("d:/hello.dll");
点击中间区域
呼出菜单
上一章
目录
下一章
×