`

JNI实例

阅读更多

JNI实例

一、JNI简介
JNI:Java Native Interface,是Java语言提供的一种通用接口,用于Java代码与本地化代码的交互。所谓本地化代码是指直接编译成的与机器相关的二进制代码, 而非Java字节码之类的中间代码。Windows下面的可执行文件,DLL等,Linux下面的可执行文件和SO文件等,都是二进制代码。
JNI允许Java语言编写的程序与其他语言编写的程序库(DLL, SO)或可执行文件进行互操作,包括汇编、C、C++。JNI产生的原因在于以下几种需求:
(1). 你的应用程序需要使用系统相关的功能,而Java代码不支持或是难以办到。这个比较典型的是实现托盘图标,有几种现成的方案都是用的JNI做的,名字好像是叫做TrayIcon和StayOnTop。当然啦,如果是用的Java1.6,那就要另当别论了。
(2). 已有其他语言写好的类库或程序,希望Java程序可以使用它们。
(3). 出于更高的性能要求,希望使用汇编或是C/C++语言来实现部分功能。
下图出自JNI Tutorial,展示了JNI的地位:


其他的理论的东西就不多说了,JNI Tutorial讲得很清楚。强烈建议阅读。

二、JNI的开发步骤
这里以使用C++编写本地化方法实现为例,开发一个使用JNI的Demo程序,具体步骤如下所示:
(1). 编写带有native方法的java类
(2). 使用javac命令编译所编写的java类
(3). 使用javah命令处理类文件,生成C/C++头文件
(4). 使用C/C++实现本地方法
(5). 将C/C++编写的文件生成动态连接库

三、Demo程序,Demo程序宣示了Java代码中调用C++的输出功能打印字符串,同时演示了使用C++的输入功能读取字符串,并使用System.out.println输出。

1. 编写带native方法的Java类
本示例中的源程序就一个Java类。如下所示:

 // HelloJNI.java -- 简单的JNI入门示例。
// 2007-4-5 16:41:45

public class HelloJNI {
   public native void displayHello () ;
   public native void showTime () ;

   private native String getLine ( String prompt ) ;

   static {
     System.loadLibrary ( "hello" ) ;
   }

   public static void main ( String [] args ) throws Exception {
     HelloJNI hj = new HelloJNI () ;

     System.out.println ( "==> Demo 1: hello" ) ;
     hj.displayHello () ;
     System.out.println ( "==> Demo 2: time" ) ;
     hj.showTime () ;

     System.out.println ( "==> Demo 3: input" ) ;
     String input = hj.getLine ( "Type a line: " ) ;
     System.out.println ( "User typed: " + input ) ;
   }
} 
 


说明:一共3个native方法,第一个简单的Hello,第二个使用<ctime>头文件中的相关函数计算当前时间,第三个读取输入。注意static语句块:

static {
        System.loadLibrary("hello");
}
 


在JVM载入HelloJNI类的时候加载动态库,System.loadLibrary()中的参数是我们要生成的动态库文件的名字,不包括扩展名,在Windows下面是hello.dll,Linux下面是hello.so,这个由Java自动识别。

2. 编译此类

3. javah HelloJNI 生成C/C++头文件,生成的头文件不用任何修改。如下所示:

 /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:      HelloJNI
* Method:     displayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloJNI_displayHello
   ( JNIEnv *, jobject ) ;

/*
* Class:      HelloJNI
* Method:     showTime
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloJNI_showTime
   ( JNIEnv *, jobject ) ;

/*
* Class:      HelloJNI
* Method:     getLine
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloJNI_getLine
   ( JNIEnv *, jobject, jstring ) ;

#ifdef __cplusplus
}
#endif
#endif
 



4. 编写C/C++实现文件,如下所示:

 // HelloJNIImpl.cpp -- 自己编写的实现文件
// 2007-4-5 16:52:53

#include <jni.h>
#include <iostream>
#include <ctime>
#include <string>
#include <cstdio>
#include <windows.h>
#include "HelloJNI.h"

extern "C" {
   //
}

using namespace std;

JNIEXPORT void JNICALL Java_HelloJNI_displayHello ( JNIEnv * env, jobject obj ) {
   cout << "Hello, JNI tech. This is from C++!" << endl;
}

JNIEXPORT void JNICALL Java_HelloJNI_showTime ( JNIEnv * env, jobject obj ) {
   time_t sec;
   tm t;

   time_t loop;

   cout << "时间:" ;
   sec = time ( NULL ) ;
   t = *localtime ( &sec ) ;
   unsigned int hour = t.tm_hour;
   unsigned int mini = t.tm_min;
   unsigned int secd = t.tm_sec;
  
   if ( hour < 10 ) {
   cout << "0" << hour;
   }
   else {
     cout << hour;
   }
   cout << ":" ;
   if ( mini < 10 ) {
     cout << "0" << mini;
   }
   else {
     cout << mini;
   }
   cout << ":" ;
   if ( secd < 10 ) {
     cout << "0" << secd;
   }
   else {
     cout << secd;
   }
   cout << endl;
}

JNIEXPORT jstring JNICALL Java_HelloJNI_getLine ( JNIEnv * env, jobject obj, jstring prompt ) {
   char buf [ 128 ] = { 0 } ;
   const char * str = ( env ) ->GetStringUTFChars ( prompt, 0 ) ;
//   printf("%s", str);
   cout << str;
   ( env ) ->ReleaseStringUTFChars ( prompt, str ) ;
   string buffer;
   getline ( cin, buffer ) ;
//   scanf("%s", buf);
   return ( env ) ->NewStringUTF ( buffer.c_str ()) ;
} 
 


说明:JNI Tutorial中使用的居然是像下面这样的代码,env指针的使用应该有误,敬请注意。

JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
    char buf[128];
    const char *str = (*env)->GetStringUTFChars(env, prompt, 0);
    printf("%s", str);
    (*env)->ReleaseStringUTFChars(env, prompt, str);
    ... 


5. 生成本地库文件。笔者使用的VS.NET 2003中的C++编译器。VS.NET 2003命令行工具生成DLL的命令:
cl -I<头文件目录1> -I<头文件目录2> -LD <C/C++源文件名> -Fe<生成的DLL文件名>
-I选项指定头文件目录,-LD指定C++源文件,-Fe指定生成的DLL文件名。将各个部分替换成实际的情况,实际使用的命令如下:
cl -IC:/java/jdk1.5.0_10/include -IC:/java/jdk1.5.0_10/include/win32 -LD HelloJNIImpl.cpp -Fehello.dll
注:cl可以增加-EHsc参数来减少生成过程中的输出信息。如下图所示:


6. 运行结果,如下图所示:


注意自己输入的那一行!

7. 自动化。其实步骤都很简单,所以可以使用Ant来完成。下面提供一个ANT Buildfile。使用之前请根据自己的实际情况修改相关属性。
注意:Builfile编码是UTF-8的。
build.xml

<?xml version= "1.0" encoding= "UTF-8" ?>
<project default = "help" basedir= "." name= "JNI_Hello" >
   <property name= "app.home" value= "." ></property>

   <!-- 设置头文件的目录,根据JDK具体的安装目录而定 -->
   <property name= "h.dir1" value= "C:/java/jdk1.5.0_10/include" ></property>
   <property name= "h.dir2" value= "C:/java/jdk1.5.0_10/include/win32" ></property>
  
   <!-- 设置cl工具的路径,视具体情况而定 -->
   <property name= "vc.bin.dir"
     value= "C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/bin" >
   </property>

   <property name= "cpp.name" value= "HelloJNIImpl.cpp" ></property>
   <property name= "dll.name" value= "hello.dll" ></property>

   <target name= "compile" description= " ==> 编译Java源文件" >
     <javac srcdir= "${app.home}" destdir= "${app.home}" >
     </javac>
   </target>

   <target name= "javah" description= " ==> 生成C/C++头文件" >
     <javah destdir= "${app.home}" force= "yes" class = "HelloJNI" />
   </target>
  
   <target name= "dll" description= " ==> 调用cl命令生成相关的DLL文件" >
     <exec dir= "${app.home}" executable= "${vc.bin.dir}/cl.exe" os= "Windows XP" >
       <!-- 参数-EHsc好像是VS.NET2003中cl.exe的,可以不加,参考下面的注释行 -->
       <arg line= "-EHsc -I${h.dir1} -I${h.dir2} -LD ${cpp.name} -Fe${dll.name}" />
       <!--
       <arg line= "-I${h.dir1} -I${h.dir2} -LD ${cpp.name} -Fe${dll.name}" />
       -->
     </exec>
   </target>

   <target name= "run" description= " ==> 运行" >
     <java classname= "HelloJNI" ></java>
   </target>

   <target name= "all" description= " ==> 自动进行上面任务列表" >
     <antcall target= "compile" />
     <antcall target= "javah" />
     <antcall target= "dll" />
     <antcall target= "run" />
   </target>

   <target name= "help" description= " ==> 显示帮助信息" >
     <echo>用法帮助:</echo>
     <echo>ant compile      编译Java源文件</echo>
     <echo>ant javah        生成C/C++头文件</echo>
     <echo>ant dll          调用cl命令生成相关的DLL文件</echo>
     <echo>ant run          运行</echo>
     <echo></echo>
     <echo>ant all          自动进行上面任务列表</echo>
     <echo>ant help         显示帮助信息</echo>
   </target>
</project>
 


Done!^_^!

JNI还有很多高级的功能,这里我就不说了,一来是不太会,二来也没什么意义。JNI Tutorial上讲得很全面,不错。

分享到:
评论
1 楼 侯上校 2011-06-25  
很好的,顶顶

相关推荐

    第一个JNI实例学习

    在这个"第一个JNI实例学习"中,我们将探讨如何创建并运行一个基本的JNI程序。 首先,我们需要理解JNI的核心概念。JNI提供了一套接口,让Java代码能够声明本地方法,这些方法在运行时由本地(非Java)代码实现。本地...

    android调用jni实例

    我们将以"android调用JNI实例"为例,一步步解释这个过程。 首先,我们需要准备开发环境。安装Android NDK是必不可少的步骤,NDK(Native Development Kit)是一组工具,开发者可以使用它来编写用C和C++编写的本地...

    jni实例 已Eclipse测试可用

    本实例是基于Eclipse的JNI应用,已经过测试,能够帮助开发者直观地理解JNI的调用流程。 首先,我们来详细了解一下JNI的基本概念。JNI提供了一种方式,让Java代码可以调用本地(非Java)代码,也可以让本地代码调用...

    JNI实例的使用

    本篇文章将深入探讨JNI实例的使用,包括基本的设置、回调机制、传递Java集合如Map到本地方法以及处理复杂对象。 首先,让我们理解JNI的基本工作原理。JNI的核心是定义了一套Java到本地代码(如C/C++)的调用规范。...

    linux JNI实例及其JNI编程模板

    本教程将深入探讨Linux环境下的JNI实例以及JNI编程模板。 1. JNI基础: JNI提供了一种标准方式,让Java虚拟机(JVM)能够调用本地方法(即非Java语言编写的函数)。本地方法通常用C或C++编写,可以充分利用硬件...

    简单的jni实例,适合初学者使用

    这个“简单的JNI实例”显然是为了帮助初学者理解和掌握JNI的基本用法。 JNI的核心概念主要包括以下几个部分: 1. **本地方法接口**:JNI定义了一组函数,这些函数在Java虚拟机(JVM)内部实现,允许Java代码调用...

    Android JNI实例01

    在这个“Android JNI实例01”中,我们将探讨如何使用JNI在Android应用中集成C/C++代码,以及如何在ARM架构的设备上运行这些本地代码。 1. **JNI基础**: - JNI接口定义了一系列函数,如`FindClass`, `GetMethodID`...

    简单jni实例调用第三方.so库

    总结来说,这个“简单JNI实例调用第三方.so库”的例子展示了如何在Java应用程序中通过JNI调用C/C++代码。这个过程包括:定义Java的native方法、使用javah生成C/C++头文件、编写C/C++实现、编译生成.so库以及在Java...

    配置NDK集成eclipse使用hello-jni实例

    **配置NDK集成Eclipse使用hello-jni实例步骤** 1. **安装Cygwin** - 访问Cygwin官方网站下载安装包,并在Windows上解压。 - 在安装过程中,选择合适的安装路径,避免包含空格和中文字符,以防止可能出现的问题。 ...

    ndk jni实例源码

    在Android开发中,NDK(Native Development...总之,"ndk jni实例源码"提供了一个基础的Android原生开发教程,通过学习和实践,开发者可以掌握在Android应用中使用C/C++代码的关键步骤,为更复杂的系统级开发打下基础。

    JNI实例 Java调用DLL c++调用Java

    总之,JNI实例“Java调用DLL c++调用Java”是一个实用的学习资源,它详细解释了如何利用JNI进行Java与C++的交互,无论是将本地库引入Java程序还是将Java功能嵌入C++应用。通过实践这些例子,开发者能够深入理解JNI的...

    JNI 实例, 可以作为模板供初学者学习. 纯C版本

    通过这个纯C版本的JNI实例,初学者可以深入了解JNI的工作原理,如何在C代码中操作Java对象,以及如何在Java和本地代码之间传递数据。同时,它也演示了如何在不同的开发环境中(如Cgwin)进行编译和链接。

    一个jni实例.doc

    在本例中,我们看到一个JNI实例的演示,它涉及到在Java程序中调用C/C++编写的本地方法。 首先,我们有一个名为`Student`的Java类,它包含了学生的基本信息,如姓名(`name`)和年龄(`age`)。这个类有对应的getter...

    JNI实例Android

    在这个"Mstar平台JNI实例"中,我们将探讨如何在Android环境中使用JNI技术实现特定的功能,如个人资料备份,并且通过了验证测试。 首先,理解JNI的基本概念是至关重要的。JNI为Java应用程序提供了一种方式,使得Java...

    java的jni实例(内有详细说明)

    本实例提供了一个使用JNI调用C++ DLL(动态链接库)的示例,对于学习和理解JNI的工作原理及其应用非常有帮助。 首先,我们来了解JNI的基本概念。JNI包含了一组头文件和库,它们定义了Java虚拟机(JVM)与本地代码...

    Android JNI 实例

    总的来说,Android JNI实例涵盖了从Java到C/C++的调用过程,涉及了JNI的基本原理和实践技巧。无论是静态注册还是动态注册,都需要理解JNI的核心概念,如JNI函数的调用约定、JNI数据类型以及Java对象在本地代码中的...

Global site tag (gtag.js) - Google Analytics