Java native 关键字

来源:互联网 发布:南京麦芽金服数据 编辑:程序博客网 时间:2024/06/05 02:58

今天在看Thread类,启动线程用的 start()方法,该方法使线程开始执行,jvm 调用这个线程的run方法。(线程不能重复start),而 start()方法中又调用了 native start0()方法,该方法没有实现体,其实现体是由非java语言在外面实现的,JVM将控制调用本地方法的所有细节。Object 类中也有很多 native 方法。

JNI

Java Native Interface (JNI)提供了若干的API实现了Java和其他语言的通信(主要是 C&C++)。简单地讲,一个Native Method就是一个java调用非java代码的接口。有了本地方法,java程序可以做任何应用层次的任务。

使用Native Method 原因

有些层次的任务用java实现起来不容易,或者对程序的效率很在意时,如果要使用一些java语言本身没有提供封装的操作系统的特性时,那么也需要使用本地方法。JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成,甚至JVM的一些部分就是用C写的。例如类 java.lang.Thread 的setPriority0()方法,这个本地方法是用 C 实现的,并被植入 JVM 内部,更多的情况是本地方法由外部的动态链接库(external dynamic link library)提供,然后被JVM调用。

JVM如何调用 Native Method

当一个类第一次被使用到时,这个类的字节码会被加载到内存。在这个被加载的字节码的入口维持着一个该类所有方法描述符的 list,这些方法描述符包含这样一些信息:方法代码存于何处,它有哪些参数,方法的描述符(public之类)等等。
如果一个方法描述符内有 native,这个描述符块将有一个指向该方法的实现的指针。这些实现在一些DLL文件内,但是它们会被操作系统加载到java程序的地址空间。当一个带有本地方法的类被加载时,其相关的DLL并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些DLL才会被加载,这是通过调用 java.system.loadLibrary()实现的。
使用 native 关键字说明这个方法是原生函数,也就是这个方法是用 C/C++ 语言实现的,并且被编译成了DLL,由java去调用。

简单例子

可以将native方法比作Java程序同C程序的接口,其实现步骤:

  1、在Java中声明native()方法,然后编译(javac);
  2、用 javah 命令产生一个.h文件;
  3、写一个 .c 文件实现 native 导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了 JDK 带的 jni.h 文件,该文件在 $JAVA_HOME/include 目录下);
  4、将第三步的 .c 文件编译成动态链接库文件;
  5、在 Java 中用 System.loadLibrary() 方法加载第四步产生的动态链接库文件,这个 native() 方法就可以在Java中被访问了。

新建个 Java 文件,内容如下。

public class HelloWorld{       public native void sayHello();       static{          System.loadLibrary("HelloWorld");       }       public static void main(String[] args){          new HelloWorld().sayHello();      }  }

按上面步骤执行命令

 javac HelloWorld.java       javah HelloWorld

HelloWorld.h 文件内容

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class:     HelloWorld * Method:    sayHello * Signature: ()V */JNIEXPORT void JNICALL Java_HelloWorld_sayHello  (JNIEnv *, jobject); #ifdef __cplusplus}#endif#endif

写个 .c 文件实现 HelloWorld.h 文件中的函数JNIEXPORT void JNICALL Java_HelloWorld_sayHello(JNIEnv *, jobject); 文件内容如下。

#include "HelloWorld.h"#include <stdio.h>JNIEXPORT void JNICALL Java_HelloWorld_sayHello(JNIEnv *env, jobject obj) {    printf("Hello World!");    return;}

生产动态链接库:

Windows——.DLL;Linux——.so;Mac OS X——.dylib; .dylib是Mach-O格式,也就是Mac OS X下的二进制文件格式。Mac OS X提供了一系列工具,用于创建和访问动态链接库。
编译器/usr/bin/cc,也就是gcc了,Apple改过的
汇编器/usr/bin/as
链接器/usr/bin/ld // 可以合并.o文件 ld -r -o c.o a.o b.o
Mac 有个自己的工具,/usr/bin/libtool,来创建动态链接库,这个libtool不是
GNU的那个同名的libtool。

//生成sayHello.occ -I"/Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home/include/" -I"/Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home/include/darwin" -c SayHello.clibtool -dynamic -o sayHello.dylib sayHello.o

生成 .o 文件时,-I 是为了能够加载到 jni.h 和 jni_md.h 文件,
发现我的 libtool 已经是gun工具的了,貌似不能用,于是就还是使用了 gcc 来生成动态链接库

gcc -fPIC -I"/Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home/include/" -I"/Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home/include/darwin" -c HelloWorld.c //生成动态链接库gcc -fPIC -dynamiclib HelloWorld.o -o HelloWorld.dylib

再运行 java 文件就可以了。

访问动态链接库
nm a.dylib可以看到导出符号表等。
另一个Mac上的常用工具是 otool ,比如想看看c.dylib的依赖关系
otool -L a.dylib

[参考]
java Native Method初涉
JAVA中NATIVE关键字的作用

1 0
原创粉丝点击