您的位置:首页 > 编程语言 > Java开发

Java native 关键字

2016-08-11 23:10 344 查看
今天在看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.o
cc -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.c

libtool -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关键字的作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: