Java中native是关键字。它一般在本地声明,异地用C和C++来实现。它的声明有几点要注意:1)native与访问控制符前后的关系不受限制。2)必须在返回类型之前。3)它一般为非抽象类方法。4)native方法在异地实现,象抽象方法一样,所以没有方法体,以分号结束。如下列5种声明:

native public void f();                         正确。

private native void f();                        正确。

protected int native f();                      错误,返回类型位置不对,返回类型必须在native之后。

public abstract native void f();            native必然不是abstract的。

native int f(){}                                     错误,因为存在方法体{}

public static native f();                         正确。static与native方法位置随意。

下例是比较典型的native的使用方式,用loadLibrary导入存在源文件目录下的*.dll文件,然后定义native方法时,与c/c++实现的函数有相同的参数和返回类型。

  1. public class OpticalFlowCalculateDll{
  2. static{
  3. System.loadLibrary("OpticalFlow");
  4. }
  5. public native static void setImage();
  6. public native static int[] getGoodFeatureListForTrack();
  7. public native static int[] getMatchedFeatureList();
  8. public native static int getFeatureListSize();
  9. public native static void dispose();
  10. }
  1. public class OpticalFlowCalculateDll{
  2. static{
  3. System.loadLibrary("OpticalFlow");
  4. }
  5. public native static void setImage();
  6. public native static int[] getGoodFeatureListForTrack();
  7. public native static int[] getMatchedFeatureList();
  8. public native static int getFeatureListSize();
  9. public native static void dispose();
  10. }

再展开来说JNI,JNI是JavaNative Interface的缩写,中文为JAVA本地调用。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。JNI是JDK的一部分,用于为Java提供一个本地代码的接口。通过使用JNI编写的程序能够确保你的代码能够完全的移植到所有的平台。JNI使得运行在JVM虚拟机上的Java代码能够操作使用其它语言编写的应用程序和库,比如 C/C++以及汇编语言等。此外JNI提供的某些API还允许你把JVM嵌入到本地应用程序中。

  

  使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。

JNI的设计目的:

  ·标准的java类库可能不支持你的程序所需的特性。

  ·或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。

  ·你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。

本文将通过一个实例来阐述使用VC++6.0来实现JNI的完整过程。使用JNI来整合本地代码和Java代码的步骤是确定的,没有再创作的余地,所以读者可以通过本文的步骤来逐步认识到,其实Java也是"没有什么不可以"的。

一、JNI的实现任务描述:在Java中调用windows下的消息框函数,并且从Java中传递一个字符串作为MessageBox函数的显示文本参数,显示在消息框的中间。下面让我们一起进入这一奇妙的旅程。

Step 1:写一个Java类,在这个类中包含了需要调用的本地方法的描述。

  1. //WinMsgBox.java
  2. package edu.netcom.jni;
  3. public class WinMsgBox
  4. {
  5. static{
  6. System.loadLibrary("WinMsgDll");    // (1)
  7. }
  8. public native void showMsgBox(String str); // (2)
  9. }
  1. //WinMsgBox.java
  2. package edu.netcom.jni;
  3. public class WinMsgBox
  4. {
  5. static{
  6. System.loadLibrary("WinMsgDll");    // (1)
  7. }
  8. public native void showMsgBox(String str); // (2)
  9. }

(1)中WinMsgDll是动态链接文件的文件名,不用加扩展名,因为在不同的平台下动态链接文件扩展名是不同的,由JVM自动识别,比如在 Solaris下,会被转换为WinMsgDll.so;而Win32环境下会转换为WinMsgDll.dll。这个文件名必须和Step 4中生成的文件名一致。这个文件的存放位置也很重要,它只能被放在JVM属性值java.library.path中指定的文件夹中。这个属性值可以使用 System.getProperty("java.library.path");来查看。一般情况下,至少放在这几个位置是确定可靠的,windows安装目录下的system32下面,JDK安装目录下的bin下面,以及调用主类文件的当前目录。

(2)中指明了你必须用本地代码实现的方法。

Step 2:提示符下使用命令javac -d . WinMsgBox.java编译Step 1编写的java文件。

此时会在当前目录下建立一个edu/netcom/jni目录结构,并且一个WinMsgBox.class文件存在其中。

Step 3:提示符下使用命令javah -jni edu.netcom.jni.WinMsgBox,此时会在当前目录下产生一个edu_netcom_jni_WinMsgBox.h文件,注意这个文件名是由(包名+类名)组成,中间用(_)隔开。此文件内容如下:

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

(1)包含的jni.h存在于JDK安装目录下的include下面。

(2)(Ljava/lang/String;)V这是函数的标记符,当从本地方法端访问Java端的方法时,会用到这个标记符。JNI中为每种数据类型也定义了标记符,标记符的规则请查看JNI标准文档。

(3)在WinMsgBox.java中本地方法void showMsgBox(String str);的定义,被映射为JNIEXPORT void JNICALL Java_edu_netcom_jni_WinMsgBox_showMsgBox(JNIEnv *, jobject, jstring); 其中函数名的映射规则是(Java_包名_类名_方法名),如果存在重载的方法,则在后面还会增加每个参数的标记符。每一个方法映射到本地C函数后都会增加两个参数:JNIEnv *和jobject,关于这两个参数的用法将在后面阐述。另外,所有Java中的数据类型都会按一定规则进行映射为本地数据类型,这些数据类型都是在 jni.h中定义的。下面分别按照基本数据类型,和对象类型列出。

Step 4:使用VC来编写本地方法的实现函数,最后编译成.dll文件。过程如下:

1) 选择new->projects(选择Win32 Dynamic-Link Library,以Step 1中指定的库名WinMsgDll作为工程名)->OK->An ampty DLL project->Finish。

2) 选择Tools->Options->Directories(添加目录D:/J2SDK1.4.2_03/INCLUDE和D: /J2SDK1.4.2_03/INCLUDE/WIN32)。在这些目录中包含JNI所需的头文件。

3) 将Step 3生成的edu_netcom_jni_WinMsgBox.h拷贝到WinMsgDll工程文件夹中。然后FileView中添加这个头文件。

4) 添加源文件WinMsgDll.cpp,内容如下:

  1. include "windows.h"
  2. #include "edu_netcom_jni_WinMsgBox.h"
  3. /*
  4. * Class:     edu_netcom_jni_WinMsgBox
  5. * Method:    showMsgBox
  6. * Signature: (Ljava/lang/String;)V
  7. */
  8. JNIEXPORT void JNICALL Java_edu_netcom_jni_WinMsgBox_showMsgBox
  9. (JNIEnv * env, jobject obj, jstring str){
  10. const char *msg;
  11. msg = env->GetStringUTFChars(str,0);
  12. MessageBox(NULL,msg,"Java invoke",MB_OK);
  13. env->ReleaseStringUTFChars(str,msg);
  14. }
  1. include "windows.h"
  2. #include "edu_netcom_jni_WinMsgBox.h"
  3. /*
  4. * Class:     edu_netcom_jni_WinMsgBox
  5. * Method:    showMsgBox
  6. * Signature: (Ljava/lang/String;)V
  7. */
  8. JNIEXPORT void JNICALL Java_edu_netcom_jni_WinMsgBox_showMsgBox
  9. (JNIEnv * env, jobject obj, jstring str){
  10. const char *msg;
  11. msg = env->GetStringUTFChars(str,0);
  12. MessageBox(NULL,msg,"Java invoke",MB_OK);
  13. env->ReleaseStringUTFChars(str,msg);
  14. }

5) 编译生成WinMsgBox.dll文件。并将这个.dll文件拷贝到Step 1中说明的目录中。

注意:

1) 我们知道dll文件有两种指明导出函数的方法,一种是在.def文件中定义,另一种是在定义函数时使用关键字 __declspec(dllexport)。而在JNI中函数定义中的关键字JNIEXPORT实际在jni_md.h中如下定义,#define JNIEXPORT __declspec(dllexport),可见JNI默认的导出函数使用第二种。使用第二种方式产生的导出函数名会根据编译器发生变化,在有的情况下会发生找不到导出函数的问题(我们在JSP中使用JNI时就发生了这种问题,百思不得其解,后来强行加入一个.def文件就解决了)。因此最好是使用第一种方法自己定义一个.def文件来指明导出函数,这种情况下会强制使用第一种方式产生导出函数。本例中可以加入一个WinMsgDll.def文件,内容如下:

LIBRARY      "WinMsgDll"

DESCRIPTION 'message Windows Dynamic Link Library'

EXPORTS

; Explicit exports can Go here

Java_edu_netcom_jni_WinMsgBox_showMsgBox

2) 从本例中,我们可以看到WinMsgBox.java决定了edu_netcom_jni_WinMsgBox.h,而后者又决定了 WinMsgDll.dll,也就是说,这是一个"牵一发而动全身"的过程,如果你改动了WinMsgBox.java,就一定要把整个步骤都走一遍(这一点一定要切记,因为这也是我们跌得鼻青脸肿后才得出的警世良言)。

3) 生成的.dll文件一定要正确拷贝到Step 1说明的目录中,本例中是将生成的WinMsgDll.dll和Step 5中的测试文件放在同一个目录下的(这也是我们困惑了很久才解决的问题)。

Step 5:编写一个测试文件来测试对WinMsgDll.dll的调用。测试文件TestJNI.java内容如下:

  1. //TestJNI.java
  2. import edu.netcom.jni.WinMsgBox;
  3. public class TestJNI
  4. {
  5. public static void main(String[] args){
  6. WinMsgBox box = new WinMsgBox();
  7. box.showMsgBox("Wonderful!!");
  8. }
  9. }
  1. //TestJNI.java
  2. import edu.netcom.jni.WinMsgBox;
  3. public class TestJNI
  4. {
  5. public static void main(String[] args){
  6. WinMsgBox box = new WinMsgBox();
  7. box.showMsgBox("Wonderful!!");
  8. }
  9. }

编译,运行,windows下的对话框跃然屏幕中间。

JAVA中native方法调用的更多相关文章

  1. java中native方法的使用

    在非常多情况下,java须要调用其它语言的代码,比方c的代码.那么这个时候java中native方法就发挥作用了.以下就介绍native方法的使用. 一.JNI使用流程 a.编写带有native声明的 ...

  2. 认识理解Java中native方法(本地方法)

      Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能. 可 ...

  3. [03]java中的方法以及控制语句

    00 Java中的语句块 语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句.块确定了局部变量的作用域.块中的程序代码,作为一个整体,是要被一起执行的.块可以被嵌套在另一个块中,但 ...

  4. 第48篇-native方法调用解释执行的Java方法

    举一个native方法调用解释执行的Java方法的实例,如下: public class TestJNI { static { System.load("/media/mazhi/sourc ...

  5. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  6. java 中使用ajax调用后台方法注意事项

    java 中使用ajax调用后台方法注意事项,后台方法一定要加@ResponseBody jQuery.validator.addMethod("checkRuleName",fu ...

  7. Java中native关键字

    Java中native关键字 标签: Java 2016-08-17 11:44 54551人阅读 评论(0) 顶(23453) 收藏(33546)   今日在hibernate源代码中遇到了nati ...

  8. Java中Native关键字的作用

    初次遇见 native是在 java.lang.Object 源码中的一个hashCode方法: 1 public native int hashCode(); 为什么有个native呢?这是我所要学 ...

  9. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

随机推荐

  1. java将字符串根据空格进行分割,使用split方法

    public class D { public static void main(String[] args) { String b = "Hello Java World"; S ...

  2. Kafka.net使用编程入门(二)

    1.首先创建一个Topic,命令如下: kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partit ...

  3. js的event.preventDefault()与event.stopPropagation()

    event.preventDefault()用法介绍 该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作).例如,如果 type 属性是 "submit" ...

  4. HTML5 ③

    超链接和锚链接: 1.超链接标签:<a herf="需要连接的页面地址"    target=“01._self :在当前页面打开 *默认值  02. _blank :新窗口 ...

  5. (C/C++学习笔记) 二十四. 知识补充

    二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...

  6. Linux 最小安装常用包

    Linux最小安装后很多常用的工具都没有,但直接通过yum install 文件名的方式可能无法找到,汇总于此,随时更新: CentOS7 1.如果要通过SecureCRT上直接上传下载文件,最简单的 ...

  7. Interlocked单向链式栈

    线程同步一大部分与原子访问(atomic access)有关, 所谓原子访问, 指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源. Interlocked单向链式栈的操作 ...

  8. centos7安装maven,git

    1.maven 下载 2.安装包 解压 3.配置maven环境变量 4.检查是否安装成功 5.检查是否安装 git 6.yum 安装 git 7.配置 git 环境变量 8.检查git是否安装成功 1 ...

  9. E - Mahmoud and Ehab and the bipartiteness CodeForces - 862B (dfs黑白染色)

    Mahmoud and Ehab continue their adventures! As everybody in the evil land knows, Dr. Evil likes bipa ...

  10. 百杂讲堂之为什么32位系统只能操作4g内存

    百杂讲堂之为什么32位系统只能操作4g内存 计算机内存中很多的单元,每一个单元就是一个字节,一个字节有8位.每一个单元有两种状态:0和1. 所以 两个单元就有4个组合: 3个单元就有8个组合: 依次类 ...