`
zhouwei064
  • 浏览: 27267 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

JNI简易使用之使用vs命令提示下创建DLL详解

    博客分类:
  • Java
阅读更多
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
定义
使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。
设计目的
标准的java类库可能不支持你的程序所需的特性。或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。


具体步骤
  • 编写带有native声明的方法的java类
  • 使用javac命令编译所编写的java类
  • 使用javah -jni java类名生成扩展名为h的头文件
  • 使用C/C++实现本地方法
  • 将C/C++编写的文件生成动态连接库
  • 导入DLL,运行程序

1.编写带有native声明的方法的java类
package jav.test.jni;

public class NativeTest {

	public static native void getHelloNative();
	
	static{
		System.loadLibrary("HelloNative");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		getHelloNative();
	}

}

2.保存后,如果没有错误eclipse会编译产生HelloNative.class文件,默认在当前工程目录下D:\eclipse-workspace\javar\bin\jav\test\jni\NativeTest.class。
3.Core Java上说在生成h头文件之前要先生成CLASS文件 :,在D:\eclipse-workspace\javar\bin目录下生成了文件jav_test_jni_NativeTest.h;但实际操作中即使先前没有生成CLASS文件,也可以直接用javah对源文件生成头文件(先通过cd命令到达D:\eclipse-workspace\javar\src)
同样会生成文件jav_test_jni_NativeTest.h,只不过该文件在目录D:\eclipse-workspace\javar\src下产生的jav_test_jni_NativeTest.h文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jav_test_jni_NativeTest */

#ifndef _Included_jav_test_jni_NativeTest
#define _Included_jav_test_jni_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jav_test_jni_NativeTest
 * Method:    getHelloNative
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jav_test_jni_NativeTest_getHelloNative
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

4.写C文件(其实也可以用C++实现),实现jav_test_jni_NativeTest.h中的函数,这里请注意函数名,c文件里的函数名跟h文件的函数名要一致,若实现函数名跟上面例子的名字不一致虽然之后可以正确编译并产生dll,但是最终运行java程序链接的时候会出错,抛出java.lang.UnsatisfiedLinkError异常。我把该C源文件放在和头文件同一个目录下,即D:\eclipse-workspace\javar\bin下,因为该C文件里头调用了h头文件;如果不在同一个目录则会出现类似错误:
将C源文件放在和头文件同一个目录下,jav_test_jni_NativeTest.c内容如下(文件名称自定义,可以不同):
#include"jav_test_jni_NativeTest.h"
#include<stdio.h>
JNIEXPORT void JNICALL Java_jav_test_jni_NativeTest_getHelloNative
  (JNIEnv * env, jclass cl)
{
printf("Hello Java Native!");
}

关于C语言代码,我没有从VS2008中新建工程项目,事实上从头到尾就只有两个文件,一个是自动生成的头文件jav_test_jni_NativeTest.h,另外一个是实现头文件函数原型的c文件jav_test_jni_NativeTest.c,截屏如下:
5.编译c文件产生dll(这个地方容易出错,以下详述)。
在控制台下>cl   -I  %java_home%/include     -I   %java_home%/include/win32    -LD   源文件    -Fe目的文件
  • 第一,以上命令的参数中,-I(include的首字母大写)表示编译包含的额外目录,-LD表示产生dll,-Fe后面表示产生dll的名字,具体的参数可以自己用cl -help命令查看;
  • 第二,-Fe后面表示产生dll的名字,中间没有空格。
  • 第三,我这里用的是VS2008自带的“Visual Studio 2008命令提示"程序,实际上可在cmd调用即将要用到C/C++编译命令cl,其配置可以参考用vs2005编译器cl在控制台下编译。
  • 第四,其中的%表示是环境变量,这需要手动设置,虽然JAVA_HOME 目录已经在环境变量中设置成为jdk的安装目录,但是不管用。会报错,原因是没有加引号,如下:
  • 第五,如果改成绝对路径,但是没有对路径加引号,也会报错:
  • 第六,为保险起见,-LD后面的参数——源文件HelloNative.c,要用绝对路径,否则报错如下:
  • 第七,1》System.loadLibrary():若采用装载Windows\System32下或jdk\bin或Tomcat\bin目录下,或其他在PATH环境变量中定义的本地链接库,这依赖于当前操作系统;若只是将DLL文件加到工程根目录下,则只能从eclipse来运行,如果此时从cmd运行则报异常。2》System.load():根据具体的目录来加截本地链接库,必须是绝对路径。

这是我的编译结果:
如果成功编译,则会在C:\Program Files\Microsoft Visual Studio 9.0\VC目录生成如下四个文件:
后面的事情,就是将HelloNative.dll放到工程目录下面,即D:\eclipse-workspace\javar下面,但此时不能直接从cmd命令行运行NativeTest,会报错如下:

克服这个问题的方法是在C:\WINDOWS\system32,或者在PATH环境变量中定义其他目录下加入HelloNative.dll,运行结果如下:
如果是在Eclipse开发环境中运行HelloNative那就比较简单了,此时HelloNative.dll可以加入当前项目根目录下,即:

或者也可以在PATH环境变量中,定义的其他目录下加入HelloNative.dll,然后直接在eclipse中run,话说在调用代码中有静态代码块System.loadLibrary("HelloNative"); 自动加载刚才忙碌半天的DLL文件,从eclipse运行效果:
最后提示一下,一旦确定native方法所在源文件的包位置和类名称,就不能改变,否则就会抛出UnsatisfiedLinkError错误。

Review
Of course, this is not particularly impressive by itself. However, if you keep in mind that this message is generated by the C printf command and not by any Java programming language code, you will see that we have taken the first steps toward bridging the gap between the two languages!
In summary, you follow these steps to link a native method to a Java program:
  1. Declare a native method in a Java class and java to get .class file .
  2. Run javah to get a header file with a C declaration for the method.
  3. Implement the native method in C.
  4. Compile the C file and place the DLL in a shared library.
  5. Load that library in your Java program.



实验环境和使用工具
  • 测试平台:windows XP
  • Java相关:Eclipse SDK 3.4.2; jdk1.6.0_14
  • C相关:Microsoft Visual Studio 2008命令提示
  • cmd命令提示程序;Notepad++文本编辑器


参考文章:
  1. eclipse下jni初试
  2. 使用vs2005和eclipse 创建jni的helloworld
  3. 用vs2005编译器cl在控制台下编译
分享到:
评论
2 楼 shiyiqianxun 2012-08-20  
  
1 楼 zhouwei064 2012-08-20  
第一次发,请轻拍。。。

相关推荐

    Java JNI例子-创建DLL、项目导入DLL、IDEA配置JNI、JNI调用DLL(该DLL同时依赖第三方DLL)

    Java JNI例子-创建DLL、项目导入DLL、IDEA配置JNI、JNI调用DLL(该DLL同时依赖第三方DLL)

    使用JNI,vs2010 生成dll, JSP中调用dll

    本教程将详细介绍如何使用JNI,Visual Studio 2010来生成DLL动态链接库,并在JSP(Java Server Pages)中调用这些DLL。 首先,让我们理解JNI的基本原理。JNI是Java平台标准的一部分,它为Java程序员提供了一种方法...

    在windows中jni(生成dll)Linux中jni(生成so),java调用曾c++

    - 使用GCC或G++:创建一个新的C++源文件,编写JNI头文件后,实现本地方法。 - 配置编译选项:使用`g++`编译器,添加`-shared`、`-fPIC`(位置独立代码)选项来生成共享库。 - 生成SO:执行编译命令,例如`g++ -...

    Java通过JNI调用C++的DLL文件.docx

    使用 JNI 将 Java 应用程序与 C++ DLL 文件集成需要以下步骤:创建一个 Java 工程,生成 `.class` 文件,使用 `javah` 命令生成 `.h` 头文件,创建一个 C++ 工程,并将生成的 `.h` 头文件复制到工程中,编写 C++ ...

    JAVA通过JNI调用C#dll的整个项目工程

    Java通过JNI调用C# DLL是一个跨平台、跨语言的技术实践,主要应用于需要利用Java的稳定性和C#的高性能场景。JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。C# ...

    Android 深入研究JNI详解

    ### Android深入研究JNI详解 #### 一、JNI与Android中的.so库载入 在深入了解JNI(Java Native Interface)之前,我们需要明确一点:Android应用程序的主要部分是基于Java开发的,并且这些Java类会被编译成Dex格式...

    Jni应用个人详解

    Jni应用详解 Jni(Java Native Interface)是一种allowing Java代码与 native 代码集成的技术,使得Java程序能够调用native方法和库。下面是Jni应用的详细解释: 一、Jni的主要作用 Jni的主要作用是让Java程序...

    使用JNA替代JNI调用DLL,并解决内存溢出问题

    ### 使用JNA替代JNI调用DLL,并解决内存溢出问题 #### 问题背景 在项目的开发过程中,常常遇到需要处理二进制流数据并对其进行解析处理的情况。这种情况下,如果上层应用平台采用的是Java开发,而底层算法或数据...

    JNI调用第三方dll实例

    在本实例中,我们将深入探讨如何使用JNI调用第三方DLL(动态链接库)文件,这是在Java应用程序中利用C++或C代码能力的常见场景。这个实例是在Visual Studio 2010环境下构建的,但请注意,其他环境可能需要不同的配置...

    JAVA JNI调用DLL完整步骤

    在某些场景下,比如调用操作系统特定的功能或者利用已有的C/C++库,我们需要使用JNI来实现Java与本地代码(如DLL动态链接库)的交互。本教程将详细介绍如何通过JNI在Java中调用DLL的完整步骤。 1. **创建Java类和...

    android通过jni执行shell命令

    JNI在各种场景下都非常有用,比如性能优化、利用系统底层功能或者如本例所示,执行系统级别的操作,例如运行shell命令。本文将深入探讨如何使用JNI在Android中执行shell命令。 首先,理解JNI的工作原理是必要的。...

    jni详解高清pdf文档

    本文旨在详细介绍Android环境下JNI的使用,帮助读者深入理解并熟练掌握这一关键技术。作者在前言中表达了对JNI编程的热爱及对未来深入研究虚拟机技术的渴望,同时也透露了对现有水平的谦逊认知,认为达到精通虚拟机...

    Java JNI调用DLL方法

    在本案例中,我们讨论的是如何使用Java JNI调用一个名为"AlarmTTS"的VC(Visual C++)动态链接库(DLL)并进行调试。 首先,我们需要了解Java部分的代码。`CallAlarmTTSDll`类是Java程序的核心,它定义了三个本地...

    andorid使用jni执行shell命令例子

    本文将详细介绍如何在Android应用中使用JNI来执行shell命令。 首先,我们需要理解JNI的概念。JNI是Java平台提供的一种机制,它允许Java代码和其他语言写的代码进行交互。通过JNI,我们可以在Java应用程序中调用C/...

    JNI DEMO:java jni技术 调用 c/c++ 的dll

    在这个"JNI DEMO"中,我们将探讨如何使用JNI来调用C/C++编译生成的DLL(动态链接库)文件。 首先,我们需要了解JNI的基本工作原理。JNI为Java程序提供了一种机制,使得Java代码可以声明native方法,这些方法在Java...

    JNI详解及实例程序(英文)

    ### JNI详解及实例程序 #### 一、JNI简介 JNI(Java Native Interface)是一种机制,它允许Java程序调用C或C++程序中的函数,同时也可以让C或C++程序调用Java程序中的方法。使用JNI的主要原因包括但不限于: 1. *...

    java使用JNI调用C++ dll库用法概述

    Java使用JNI(Java Native Interface)调用C++ DLL库是一种常见的技术,特别是在需要利用Java的跨平台特性同时利用C++的高效性能时。JNI提供了一种桥梁,使得Java代码能够直接与本地代码交互,比如C++编译的动态链接...

    jni调用第三方dll最简单的实例

    总结来说,这个实例展示了如何使用JNI调用第三方DLL的基本步骤:在Java中声明native方法,生成JNI头文件,实现C/C++代码并调用DLL函数,最后编译生成本地库。虽然这是一个简单的例子,但理解这些基本概念对于深入...

Global site tag (gtag.js) - Google Analytics