zoukankan      html  css  js  c++  java
  • java初探native

    最近碰见一个java中一个native关键字,不知道是干什么的,如下:

    public native String FileName(String strURL);
        static{
            System.loadLibrary("fill-jni");
        }

    上网查了下,在众多的参考资料中,下面这个链接写的还是蛮不错的:

    http://blog.csdn.net/xw13106209/article/details/6989415

    以下为转载,其中部分有备注(红色字体部分),记录一下遇到的问题。

    2.1.native关键字用法

    native是与C++联合开发的时候用的!使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。 这些函数的实现体在DLL中,JDK的源代码中并不包含,你应该是看不到的。对于不同的平台它们也是不同的。这也是java的底层机制,实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。总而言之:

    1. native 是用做java 和其他语言(如c++)进行协作时使用的,也就是native 后的函数的实现不是用java写的。
    2. 既然都不是java,那就别管它的源代码了,我们只需要知道这个方法已经被实现即可。
    3. native的意思就是通知操作系统, 这个函数你必须给我实现,因为我要使用。 所以native关键字的函数都是操作系统实现的, java只能调用。
    4. java是跨平台的语言,既然是跨了平台,所付出的代价就是牺牲一些对底层的控制,而java要实现对底层的控制,就需要一些其他语言的帮助,这个就是native的作用了
    2.2JNI简介

    native方法是通过java中的JNI实现的。JNI是Java Native Interface的 缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计 的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。

    目前java与dll交互的技术主要有3种:jni,jawin和jacob。Jni(Java Native Interface)是sun提供的java与系统中的原生方法交互的技术(在windowslinux系统中,实现java与native method互调)。目前只能由c/c++实现。后两个都是sourceforge上的开源项目,同时也都是基于jni技术的windows系统上的一个应用库。Jacob(Java-Com Bridge)提供了java程序调用microsoft的com对象中的方法的能力。而除了com对象外,jawin(Java/Win32 integration project)还可以win32-dll动态链接库中的方法。就功能而言:jni >> jawin>jacob,其大致的结构如下图:

    就易用性而言,正好相反:jacob>jawin>>jni。

    Jvm封装了各种操作系统实际的差异性的同时,提供了jni技术,使得开发者可以通过java程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互,使用其他技术实现的系统的功能;同时其他技术和系统也可以通过jni提供的相应原生接口开调用java应用系统内部实现的功能。

    在windows系统上,一般可执行的应用程序都是基于native的PE结构,windows上的jvm也是基于native结构实现的。Java应用体系都是构建于jvm之上。

    Jni对于应用本身来说,可以看做一个代理模式。对于开发者来说,需要使用c/c++来实现一个代理程序(jni程序)来实际操作目标原生函数,java程序中则是jvm通过加载并调用此jni程序来间接地调用目标原生函数。

    2.3JN的书写步骤
    1. 编写带有native声明的方法的java类,生成.java文件
    2. 使用javac命令编译所编写的java类,生成.class文件
    3. 使用javah -jni java类名生成扩展名为h的头文件,也即生成.h文件
    4. 使用C/C++(或者其他编程想语言)实现本地方法,创建.h文件的实现,也就是创建.cpp文件实现.h文件中的方法
    5. 将C/C++编写的文件生成动态连接库,生成dll文件

    3.JNI实例

    下列是所有操作都是在目录:D:JNI 下进行的,这样做的好处是便于控制。还有另外一个要求是我们的java类不含包名,当前我只测试成功不含包名的类型。

    3.1.编写带有native声明的方法的java类:HelloWorld.java

    [java] view plaincopy

    1. public class HelloWorld { 
    2. public native void displayHelloWorld();// java native方法申明
    3. static { 
    4.         System.loadLibrary("HelloWorldImpl");// 装入动态链接库,"HelloWorldImpl"是要装入的动态链接库名称。
    5.     } 
    6. public static void main(String[] args) { 
    7. // TODO Auto-generated method stub
    8.         HelloWorld helloWorld = new HelloWorld(); 
    9.         helloWorld.displayHelloWorld(); 
    10.     } 
    3.2.使用javac命令编译所编写的java类

    [java] view plaincopy

    1. d:JNI>javac HelloWorld.java 

    执行完上述命令以后生成D:JNIHelloWorld.class文件

    注:在这一步中遇到了一个从来没有遇到过的错误,我是用过notepad++写的上面程序,用这个命令编译后出现下面的错误:

    error

    原因是因为我使用的notepad++编码方式是UTF-8,改成ANSI编码方式后就可以解决上面的问题了。

    3.3.使用javah -jni java类名生成扩展名为h的头文件

    [java] view plaincopy

    1. d:JNI>javah -jni HelloWorld 

    注:使用javah/h 可以查看帮助。如下:

    用法:
      javah [options] <classes>其中, [options] 包括:
      -o <file>                输出文件 (只能使用 -d 或 -o 之一)
      -d <dir>                 输出目录
      -v  -verbose             启用详细输出
      -h  --help  -?           输出此消息
      -version                 输出版本信息
      -jni                     生成 JNI 样式的标头文件 (默认值)
      -force                   始终写入输出文件
      -classpath <path>        从中加载类的路径
      -bootclasspath <path>    从中加载引导类的路径
    <classes> 是使用其全限定名称指定的
    (例如, java.lang.Object)。

    执行完上述命令以后生成D:JNIHelloWorld.h文件,该文件内容如下:

    [java] view plaincopy

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

    这里我们可以这样理解:这个h文件相当于我们在java里面的接口,这里声明了一个 Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致

    3.4.使用C/C++实现本地方法

    创建HelloWorldImpl.cpp,代码如下所示:

    [java] view plaincopy

    1. #include "HelloWorld.h"
    2. #include <stdio.h> 
    3. #include <jni.h> 
    4. /*
    5. * Class:     HelloWorld
    6. * Method:    displayHelloWorld
    7. * Signature: ()V
    8. */
    9. JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld 
    10.   (JNIEnv *, jobject) 
    11.     printf("Hello World! "); 
    12. return; 
    注:这个程序编译时提示错误,
    image

    好吧,错误还真不少,我的路走的还挺坎坷……找啊,找啊……找到的解决方法如下:

    找到你的虚拟机安装目录,将其下面的三个文件,如下:

    jdkincludejni.h

    jdkincludewin32jawt_md.h

    jdkincludewin32jni_md.h

    分别复制它们到vc目录下的include文件夹下,一定是include文件夹啊,里面有好多的.h文件……

    然后再运行,就没有错了,如果你在这儿不修正这个错误,下面在你编译dll文件的时候,还得修复!

    3.5.将C/C++编写的文件生成动态连接库

    D:Program FilesJavajdk1.6.0_26includejni.hD:Program FilesJavajdk1.6.0_26includewin32jni_md.h这两个文件拷贝到D:JNI目录下。与HelloWorldImpl.cpp同目录,目录结构如下图所示:

    3.7 执行 cl/LD D:JNIHelloWorldImpl.cpp  得到HelloWorldImpl.dll文件

    我使用的是visual studio 2010,要使用其中的cl命令,必须打开visual studio 命令行,如下图所示:

    然后再命令行中输入如下命令

    [java] view plaincopy

    1. cl/LD D:JNIHelloWorldImpl.cpp   

    具体如下图所示:


    执行完上述命令以后,我们在C:Program Files (x86)Microsoft Visual Studio 10.0VC可以看到生成的四个文件,分别是:

    • HelloWorldImpl.dll
    • HelloWorldImpl.exp
    • HelloWorldImpl.lib
    • HelloWorldImpl.obj

    将其中的HelloWorldImpl.dll拷贝到D:JNI目录下。

    注:如果你找不到这四个文件,将目录向上推一级吧……或许你就看到了……

    3.8.执行class得到结果

    在cmd中运行:

    [java] view plaincopy

    1. d:JNI>java HelloWorld 

    具体如下图所示:

    注:人生之路太坎坷啊,我不就是想了解一下native是干啥嘛,此处又让我遇到了一个坎儿,报错如下:

    image

    我真想说一句,你妹的。解决方案是……网上说,换虚拟机,因为我的虚拟机是64位的,32位的dll文件不能运行。解决方法如下:

    解决方法来自:http://blog.csdn.net/gumanren/article/details/6455991

    1.重新下载一个32位的虚拟机,例如:jre-6u23-windows-i586.exe
    2.安装虚拟机,目录所在位置——例如:C:/Java/jre-6u23-windows-i586
    2.卸载WTK
    3.安装WTK,虚拟机地址,选择2步骤,的目录地址
    4.重启eclipse,找到设备管理器,更新模拟器位置。
    5.OK!

    到底能不能ok我是没有时间去试验了……暂时还不想重新装虚拟机……还有好多事情要忙……所以初探java的native到此结束……

    希望可以对你有帮助,嘿嘿……按照这位仁兄写的东西,文件已经整出来了,如下:

    image

    就是因为虚拟机不兼容问题运行不了,我打包一下放在csdn论坛里,你可以下载一下,但是你的虚拟机得是32位啊,要不然,你下载了也白下……

    下载地址:http://download.csdn.net/detail/still_ice_water/6363107

    4.在eclipse下运行

    • 4.1在eclipse下创建一个叫做jnitest的project
    • 4.2添加一个同3.1一样的HelloWorld.java
    • 4.3保存HelloWorld.java以后在jnitestin目录下会生成HelloWorld.class。
    • 4.4根据根据HelloWorld.class生成HelloWorld.h文件
    • 4.5创建HelloWorldImpl.cpp来实现HelloWorld.h中的方法
    • 4.6使用Visual studio 2010生成HelloWorldImpl.dll
    • 4.7在Eclipse中运行HelloWorld程序,报错如下:

    [java] view plaincopy

    1. java.lang.UnsatisfiedLinkError: no HelloWorldImpl in java.library.path 
    2.     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1738) 
    3.     at java.lang.Runtime.loadLibrary0(Runtime.java:823) 
    4.     at java.lang.System.loadLibrary(System.java:1028) 
    5.     at HelloWorld.<clinit>(HelloWorld.java:6) 
    • 4.8将HelloWorldImpl.dll拷贝到C:WindowsSystem32
    • 4.9再次执行HelloWorld程序,程序正常运行,console输出“Hello World!”


    作者:KillerLegend
    出处:http://www.cnblogs.com/KillerLegend/
    分享最新的资源,分享个人所得,欢迎关注我的新浪微博
    新浪微博主页:ikey4u
    我的个人博客:www.ikey4u.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

     
  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/killerlegend/p/3355612.html
Copyright © 2011-2022 走看看