使用Java调用C/C++

我们知道Java是一种平台无关性的语言,平台对于上层的java代码来说是透明的,所以在多数时间我们是不需要调用本地方法,但是假如你遇到了以下情况,你可能就需要使用Java调用本地方法了:

  • 你的Java代码需要得到一个文件的属性。但是你找遍了JDK帮助文档也找不到相关的API。
  • 在本地还有一个别的系统,不过它不是Java语言实现的,这个时候你需要把两套系统整合到一起。
  • 你的Java代码中需要用到某种算法,不过算法是用C实现并封装在动态链接库文件(DLL)当中的。

 

对于上述的三种情况,如果没有JNI的话,那就会变得异常棘手了。JNI其实是Java Native Interface的简称,也就是java本地接口。它提供了若干的API实现了和Java和其他语言的通信(主要是C&C++)。

 

在Java中有一些native方法,这些方法只有方法签名但是没有方法体。其实这些naive方法就是我们说的 java native interface。它提供了一个调用(invoke)的接口,然后用C或者C++去实现。

 

 

JNI概述

JVM封装了各种操作系统实际的差异性的同时,提供了JNI技术,它是一种双向的接口,使得开发者可以通过Java代码调用到各种native的库,反之亦然。所以JNI(Java Native Interface)能作为Java语言的一部分,她能够作为粘合剂将Java应用和其他本地应用(C/C++,Delphi)集合在一起。

 

JNI

 

作为一个双向的接口,JNI能支持两种native代码:native libraries 和native applications。

  • 你能使用JNI去写一些native methods去允许Java Applications能呼叫native libraries中的函数,native methods的具体实现是可能C,C++或者Delphi。
  • JNI也支持嵌入一个JVM实现到一个本地应用程序中去,去执行那些用Java语言编写的的模块.比如,一个C++编写的浏览器利用内嵌的JVM去执行下载到本地的applet。

 

实现步骤:

1) 完成Java代码,编写好Java调用类。

2) 编译你的Java类。

3) 用javah生成编译好的class文件对应的C/C++ 函数的头文件。

4) 实现头文件中的函数原型,编写native代码。

5) 将native代码编译打包成DLL库(win32)或共享库(Linux)。

6) 将你的Java代码跑起来

 

 

例子

 

1. 编写Java代码。

注意:

(1) 调用本地代码的java方法,要设置成native的。

(2) 要使用System的LoadLibrary方法去加载包含本地方法实现的库。

 

Java代码   收藏代码
  1. package eric.test;  
  2.   
  3. public class JNITest {  
  4.       
  5.     static {  
  6.         System.loadLibrary("JNITest");  
  7.     }  
  8.       
  9.     public static native void sayHelloWorld(String msg);  
  10.       
  11.     public static void main(String[] args) {  
  12.         sayHelloWorld("Hello, world");  
  13.     }  
  14. }  
 

2. 编译生成的class文件:JNITest.class

 

3. 在命令行下使用javah生成C/C++头文件。在工程的bin目录下输入以下命令:

 

Cmd代码   收藏代码
  1. javah -classpath . -jni eric.test.JNITest  

 
将生成头文件eric_test_JNITest.h,内容如下:

 

Cpp代码   收藏代码
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class eric_test_JNITest */  
  4.   
  5. #ifndef _Included_eric_test_JNITest  
  6. #define _Included_eric_test_JNITest  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     eric_test_JNITest  
  12.  * Method:    sayHelloWorld 
  13.  * Signature: (Ljava/lang/String;)V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_eric_test_JNITest_sayHelloWorld  
  16.   (JNIEnv *, jclass, jstring);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  
 

注意,在执行javah的时候,要输入完整的包名和类名。否则在以后的测试调用过程中会发生java.lang.UnsatisfiedLinkError这个异常。

 

4. 实现C++代码。在VS2008中创建一个Win32 project,类型为DLL。

 

将刚才生成的头文件eric_test_JNITest.h拷到工程目录下,并且在项目中导入到Header Files里面。打开StdAfx.h文件,在最后面添加:

 

Cpp代码   收藏代码
  1. #include "jni.h"  
  2. #include "eric_test_JNITest.h"  

 

打开JNITest.cpp文件,在其中添加实现代码。函数名为头文件中定义的函数声明。

 

Cpp代码   收藏代码
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. JNIEXPORT void JNICALL Java_eric_test_JNITest_sayHelloWorld  
  5.   (JNIEnv* env, jclass method, jstring param)  
  6. {  
  7.     const char* pt = env->GetStringUTFChars(param, 0);   
  8.     cout << pt << " called by Java Native Interface" << endl;   
  9. }  

 

其中,GetStringUTFChars是jre中提供的jni方法,用来得到java string的字符串。

 

5. 构建C++项目。会出现"Cannot open include file: 'jni.h': No such file or directory"的错误,解决方法是将以下文件拷贝到C++工程目录下

  • %JAVA_HOME%\include\jni.h
  • %JAVA_HOME%\include\win32\jni_md.h

同时将头文件eric_test_JNITest.h中的 #include <jni.h> 改为

 

Cpp代码   收藏代码
  1. #include "jni.h"  

 

然后重新build,将在debug目录下生成JNITest.dll文件。

 

6. 将dll文件复制到Java工程的bin目录下(这个位置十分重要,否则会出现not found的异常),并运行程序

 

Cmd代码   收藏代码
  1. java eric.test.JNITest  
 

将输出结果"Hello, world called by Java Native Interface"。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值