native

作者: 时待吾 | 来源:发表于2017-04-25 15:23 被阅读14次

    native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。

    凡是一种语言,都希望是纯。比如解决某一个方案都喜欢就单单这个语言来写即可。Java平台有个用户和本地C代码进行互操作的API,称为Java Native Interface (Java本地接口)。

    http://www.cnblogs.com/Alandre/p/4456719.html

    创建一个Java类,里面包含着一个 native 的方法和加载库的方法 loadLibrary。HelloNative.java 代码如下:

    native 关键字告诉编译器(其实是JVM)调用的是该方法在外部定义,这里指的是C。

    public class HelloNative

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

    @SuppressWarnings("static-access")

    public static void main(String[] args){new HelloNative().sayHello();}}

    那个加载库的到后面也起作用。native 关键字告诉编译器(其实是JVM)调用的是该方法在外部定义,这里指的是C。如果大家直接运行这个代码,  JVM会告之:“A Java Exception has occurred.”控制台输出如下:Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path at java.lang.ClassLoader.loadLibrary(Unknown Source) at java.lang.Runtime.loadLibrary0(Unknown Source) at java.lang.System.loadLibrary(Unknown Source) at HelloNative.(HelloNative.java:5)

    运行javah,得到包含该方法的C声明头文件.h    ->  

    根据头文件,写C实现本地方法  ->

    生成dll共享库,然后Java程序load库,调用即可。

    HelloNative.h文件

    /* DO NOT EDIT THIS FILE - it is machine generated */

    #include

    /* Header for class HelloNative */

    #ifndef _Included_HelloNative

    #define _Included_HelloNative

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

    * Class:     HelloNative

    * Method:    sayHello

    * Signature: ()V

    */

    JNIEXPORT void JNICALL Java_HelloNative_sayHello

    (JNIEnv *, jclass);

    #ifdef __cplusplus

    }

    #endif

    #endif

    jni.h 这个文件,在/%JAVA_HOME%include

    3、根据头文件,写C实现本地方法

    这里我们简单地实现这个sayHello方法如下:

    #include "HelloNative.h"

    #include

    JNIEXPORT void JNICALL Java_HelloNative_sayHello

    {printf("Hello,JNI");}

    生成dll共享库,然后Java程序load库,调用即可。在Windows上,MinGW GCC 运行如下:

    gcc -m64  -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk1.7.0_71\include" -I"C:\Program Files\Java\jdk1.7.0_71\include\include\win32" -shared -o HelloNative.dll HelloNative.c

    -m64表示生成dll库是64位的。然后运行HelloNative: java HelloNative



    JNI调用C 流程

    JNI是Java本机接口(JavaNativeInterface),是一个本机编程接口,它是Java软件开发工具箱(JavaSoftware Development Kit,SDK)的一部分。JNI允许Java代码使用以其他语言编写的代码和代码库。Invocation API(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用Java代码。

    不过,对Java外部的调用通常不能移植到其他平台,在applet中还可能引发安全异常。实现本地代码将使您的Java应用程序无法通过100%纯Java测试。但是,如果必须执行本地调用,则要考虑几个准则:

    1.将您的所有本地方法都封装到一个类中,这个类调用单个的DLL。对每一种目标操作系统平台,都可以用特定于适当平台的版本的DLL。这样可以将本地代码的影响减少到最小,并有助于将以后所需要的移植问题考虑在内。

    2.本地方法尽量简单。尽量使您的本地方法对第三方(包括Microsoft)运行时DLL的依赖减少到最小。使您的本地方法尽量独立,以将加载您的DLL和应用程序所需的开销减少到最小。如果需要运行时DLL,必须随应用程序一起提供。

    JNI的书写步骤如下:

    a.编写带有native声明的方法的Java

    b.使用javac命令编译编写的Java

    c.使用java-jni ****来生成后缀名为.h的头文件

    d.使用其他语言(C、C++)实现本地方法

    e.将本地方法编写的文件生成动态链接库

    以下是一个在Java中调用本地C程序的简单的例子:

    a.编写HelloWorld.java

    class HelloWorld{

    publicnativevoid hello();

    static{

    System.loadLibrary("hello");

    }

    public static void main(String[] args){

    new HelloWorld().hello();

    }

    }

    声明native方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明改方法为native的,并且不能实现。其中方法的参数和返回值在后面讲述。

    Load动态库:System.loadLibrary("hello");加载动态库(我们可以这样理解:我们的方法hello()没有实现,但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化)这里一般是以static块进行加载的。同时需要注意的是System.loadLibrary();的参数“hello”是动态库的名字。

    b.编译

    javac HelloWorld.java

    c.生成.h文件

    javah -jni HelloWorld

    示例比如说 类文件在D:\project\sparkStreamingLearn\src\main\java\TestNative\HelloWorldnative.java

    使用javah 时注意执行位置是源代码目录 D:\project\sparkStreamingLearn\src\,

    classpath是 载入类的路径 是 D:\project\sparkStreamingLearn\src\main\java\

    对应的类为:TestNative包下的HelloWorldnative.java  -jni 路径是包名+类名 即 TestNative\HelloWorldnative.java

    -d 输出目录(可以任意指定) 即TestNative_HelloWorldnative.h文件的输出目录 当前可以指定为D:\project\sparkStreamingLearn\src\main\java\TestNative\

    结果为: D:\project\sparkStreamingLearn\src\main\java\TestNative\TestNative_HelloWorldnative.h

    我们要开始写javah的命令,以便生成对应的C语言头文件

    D:\我的文档\workspace\PrepareForExam\src>javah -classpath D:\我的文档\workspace\PrepareForExam\bin -d d:/ -jni

    com.example.myclass.jni_test

    其中java中各个命令的意思是

    -classpath <路径> 用于装入类的路径

    -d <目录> 输出目录

    -jni 生成 JNI样式的头文件(默认)

    注意到以上我们命令中指定的路径

    注意到我们的命令符的执行位置是源代码目录”D:\我的文档\workspace\PrepareForExam\src”

    -classpath  后面的路径是指包”com.example.myclass”所在的根路径

    -jni 后面的路径是包名+类名

    生成内容如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */

    #include

    /* Header for class HelloWorld */

    #ifndef _Included_HelloWorld

    #define _Included_HelloWorld

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

    * Class:     HelloWorld

    * Method:    hello

    * Signature: ()V

    */

    JNIEXPORT void JNICALLJava_HelloWorld_hello

    (JNIEnv *, jobject);

    #ifdef __cplusplus

    }

    #endif

    #endif

    第一个参数是调用JNI方法时使用的JNI Environment指针。第二个参数是指向在此Java代码中实例化的Java对象HelloWorld的一个句柄。其他参数是方法本身的参数

    d.c实现

    #include

    #include "HelloWorld.h"

    #include

    JNIEXPORT void JNICALLJava_HelloWorld_hello(JNIEnv *env,jobject obj){

    printf("Hello World!\n");

    return;

    }

    其中,第一行是将jni.h文件引入(在%JAVA_HOME%\include目录下),里边有JNIEnv和jobject的定义。

    e.编译c实现

    cl -- vs201X 的安装目录下 Common7/Tools/Shortcuts/VS2013开发人员命令提示  开始cl 命令行  c/c++ 编译器  这里以在Windows中为例,需要生成dll文件。在保存HelloWorldImpl.c文件夹下面,使用VC的编译器cl成。是-I  搜索其后添加所需文件所在的目录 注意需要添加"" 即"java_home%\include" -LD  是创建.dll

    这里以在Windows中为例,需要生成dll文件。在保存HelloWorldImpl.c文件夹下面,使用VC的编译器cl成。

    cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll

    注意:生成的dll文件名在选项-Fe后面配置,这里是hello,因为在HelloWorld.java文件中我们loadLibary的时候使用的名字是hello。当然这里修改之后那里也需要修改。另外需要将-I%java_home%\include -I%java_home%\include\win32参数加上,因为在第四步里面编写本地方法的时候引入了jni.h文件。

    6) 运行程序

    javaHelloWorld就ok了!

    javac  出现错误 不是内部或外部命令,也不时可运行的程序  修改path 添加 %Java_home%/bin;%Java_home%/jre/bin;

    javac 出现中文乱码 修改方法: javac -encoding "UTF-8" HelloWorldnative.java

    相关文章

      网友评论

          本文标题:native

          本文链接:https://www.haomeiwen.com/subject/jypvzttx.html