C++ 与 Java 混合编程
C++ 与 Java 混合编程
作者:赖锋
下载源代码
现在的程序员,不再像以前一样,掌握一种编程语言就可以混得有模有样了,现实的情况是,真实的项目中,通常是涉及多种编程语言,举几个简单的例子,一个软件为了快速开发,可能是使用 Delphi 或 VB 作为界面开发首选语言,底层的指令或核心算法,会使用 C/C++ 处理,涉及数据处理的时候,为了安全和快速开发,会使用 Javascript 或 Python 等脚本语言实现数据分析处理。因此,开发者应该学习或掌握语言混合编程。 C++ 和 Java 是主流的两种编程语言,但是现在整个网上对实现这两种语言混合编程的资料少之又少,却又说之不全,并且有时多种问题现在也含糊不清,对正在学习或使用这两种语言的朋友造成很大的困扰。本人的这篇拙作,希望对使用这两种语言混合编程学习的朋友可以抛砖引玉。
实现原理
实现 Java 和 C++ 的交互,使用的技术是称为 JNI( Java Native Interface ),C++ 编写的程序,只要实现 JNI 生成的接口,则可以让 Java 程序调用,而 Java 编写的程序,C++ 调用,则需要运行 Java 虚拟机,通过 JNI 查询调用 Java 实现的方法。
环境变量设置
本文中使用的 Java 的版本是( build 1.6.0_03-b05 ), C++ 的版本为 VC++ 6.0 版本。并根据你本机上的 Java 和 C++ 安装目录设置以下的环境变量
注意不要缺少 Java 的 include 和 lib 这三个红线标出部分(为源码包文件中的 cpp-env.Bat 这个批处理文件)。
设置 Java 的环境变量,如下图所示
注意红线标注的这处部分,这部分与 C++ 调用 Java 的方法时候影响非常重要(为源码包文件中的 java-env.Bat 这个批处理文件)。 在 command 模式运行这两个批处理文件后,就可以在 command 模式运行 demo 程序了。
Java 调用 C++ 的方法
源码文件中 %SRC%/Java-cpp 目录中的 WinFile.java 的这个文件(Java 语法规定类名与文件名必须一致),定义了一个 WinFile 类,这个类的内容如下
在代码的第 18 行,声明一个带 native 属性的方法 GetFilesFromDir,这个方法传入一个字符类参数,并返回一个字符类参数,而 System.loadLibrary 则会加载指定的共享链接库,参数所示加载的动态库为 libwinfile.dll,在 windows 平台上,执行时会自动加入后缀 .dll。 在 command 模式运行以下命令:
第一条命令则会生成 WinFile.class 的编译文件,而第二条命令则会生成 WinFile.h 这个头文件,这个头文件包含了 WinFile.java 中的 native 的方法的 C/C++ 语言的定义。
在 C/C++ 的语言定中,Java 语言的 String 的定义为 jstring,注意,Java 的语言的字符与程序的编码都是以 UTF-8 编码实现的,所以 Java 中的中文字符在 C++ 的方法中如果没有编码转换,则会显示为乱码。同理,在 C++ 的方法中将中文字符返回给 Java,如果没有将字符编码转为 UTF-8,在 Java 的方法显示同样会是乱码。
以上为 %SRC%/Java-cpp/WinFile.cpp 的部分代码,代码中实现了两个函数,一个是将 UTF-8 转为 GB2312,另一个为将 GB2312 转为 UTF-8,而 jni.h 这个头文件中也同时提供了 jstring 与 char* 的类型之间转换函数。
GetStringUTFChars
NewStringUTF
运行如下编译命令:
cl -GX -LD WinFile.cpp -FelibWinFile.dll
则生成 libWinFile.dll 这个动态库(注意,生成的名称要与 System.loadLibrary 这个函数内的参数的名称一致),运行这个 Java 的类。
则输出如下
C++ 调用 Java 类方法
这里演示 String 作为参数的调用返回的方法,其它的类型的方法调用也类似。
创建一个静态声明的 Java 方法
这个方法将会接受一个 C++ 的传入的字符参数,并返回 Java 的字符类,让 C++ 函数输出内容。代码位于 %SRC%/cpp-java/WinFile.java
编译该文件后生成是一个 java 字节码的文件,它必须要运在 JVM 上,C++ 要执这些 Java 字节码,必须要运行 JVM,运行 JVM 的代码位于文件 %SRC%/cpp-java/WinFile.cpp 中,如下图所示
通过 JNI_CreateJavaJVM 这个函数,C++ 则会运行 JVM,注意,生成的 WinFile.exe 这个文件提示需要 jvm.dll,但是千万不要将 jvm.dll 从 jre 这个目录拷贝到 WinFile.exe 这个目录,因为 jvm 能够正常运行,必须依赖 jre 的 java 库和其它的动态库,虽然从 dependency 看不出 jvm.dll 依赖 jre 中的其它库和文件。如果把 jvm.dll 抽离出来与 WinFile.exe 位于同一目录,虽然能够运行,但 JNI_CreateJavaJVM 调用永远失败的。解决方法,就是将 jvm.dll 这个动态库加入的搜索路径中,如上面的批处理文件所示。
成功建立 Java 虚拟机后,就需要动态获得类名,并通过类名和函数签名获得 Java 的方法,获得函数签名的方法是运行如下命令。
Java -s -p WinFile
则输出了我们在 Java 文件中定义的函数的签名,
剩下的事情就是要负责将字符的参数进行编码调用,如下图标注出值得注意的地方
参数的转换过程是为 char* 转为 UTF8 编码再转变成为 jstring 伟入 java 方法,java 方法的返回值也应该是先转成 jstring 类型,再转为 char* 类型再转为 GB2312。运行程序,输出结果如下
总结
混合语言编程要注意的是编码传输,语言运行环境的因素。例如要在 C++ 中构造 Java 的运行环境。混合语言编程有困难,但也很有趣,两种语言的优点都可以得到,不是很好的事情吗?
原文链接:http://www.vckbase.com/document/viewdoc/?id=1889