欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java源码分析-native方法的调用

程序员文章站 2022-03-30 11:18:24
java源码分析-native方法的调用​这段时间在分析java源码时,经常能看到很多的底层源码中都调用了被native关键字修饰的方法,也就是java调用本地方法。但是在进行debug时有进不去,看不了具体的实现。因为这写方法是用c/c++实现的,那么这对我们分析源码就有了很多的阻碍,这些方法就像黑盒一样。于是我就在想,java是怎么调用这些本地方法的呢?接下来我们就一步步的探究一下这其中的原理。那么这一篇我们就来自己来通过java实现native方法的调用。1.什么是native方法​nat...

java源码分析-native方法的调用

​ 这段时间在分析java源码时,经常能看到很多的底层源码中都调用了被native关键字修饰的方法,也就是java调用本地方法。但是在进行debug时有进不去,看不了具体的实现。因为这写方法是用c/c++实现的,那么这对我们分析源码就有了很多的阻碍,这些方法就像黑盒一样。于是我就在想,java是怎么调用这些本地方法的呢?接下来我们就一步步的探究一下这其中的原理。

那么这一篇我们就来自己来通过java实现native方法的调用。

1.什么是native方法

​ native是java的关键字,用来标识某个方法为本地方法。我们知道java语言的执行是依赖于java虚拟机的,java文件被编译成能够被java虚拟机识别并执行的字节码文件,java虚拟机根据字节码文件中的命令调用操作系统相关指令,完成相关的功能。所有java语言无法直接操作操作系统指令,中间隔了一层JVM。但是c/c++这类高级语言却可以直接与操作系统打交道。于是乎就产生了这样的想法:java通过调用c/c++的方式来完成相应的与操作系统相关的底层动作,这其实就是JNI(java native interface)技术。

2.简单的JNI案例

我们的操作环境是给予Linux系统。

2.1简单的java类

/**
 * java JNI 技术
 * 模拟java调用C
 */
public class JNIDemo {
    {
        //系统加载其他语言的函数
        System.load("/home/sj/jni/test/cJNI.so");
    }

    //native标识本地方法
    public native void helloJNI();

    public static void main(String[] args) {
        new JNIDemo().helloJNI();
    }
}

将java文件上传至linux系统/home/sj/jni/test。

2.2编译获取字节码文件

直接在改路径下通过java编译命令生成字节码文件。

java JNIDemo.java

这样该路径下就会生成.class字节码文件:
java源码分析-native方法的调用

2.3javah命令

在该路径下使用javah命令生成头文件。

javah JNIDemo

执行后生成,会生成JNIDemo.h文件:

java源码分析-native方法的调用

可以看一下这个文件,vim打开:

#include <jni.h>
/* Header for class JNIDemo */

#ifndef _Included_JNIDemo
#define _Included_JNIDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNIDemo
 * Method:    helloJNI
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNIDemo_helloJNI	# 这里就是java文件中cMethod方法的签名。
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

JNIEXPORT void JNICALL Java_JNIDemo_helloJNI 这句需要我们关注,因为后面的c语言实现的方法必须“Java_JNIDemo_helloJNI”一致。

2.4用C写一个native方法

下面我们模拟一个C方法:

vim cjni.c
#include <stdio.h> //头文件
#include "JNIDemo.h" // java文件头,这里一定要加上上面java语言的头文件

// 这就是上面头文件中的cMethod方法的具体实现,注意方法签名不能变,一定要和头文件一样。
JNIEXPORT void JNICALL Java_JNIDemo_helloJNI(JNIEnv *env, jobject c1)
{
    // 如果java调用cMethod方法成功,则会打印这句话
    printf("hello jni! success ! \n");
}

下面使用cjni.c生成动态链接库文件:cJNI.so

gcc  -fPIC -I /opt/jdk1.8.0_211/include  -I /opt/jdk1.8.0_211/include/linux   -shared -o cJNI.so cjni.c

/opt/jdk1.8.0_211/include和/opt/jdk1.8.0_211/include/linux分别是linux系统安装jdk源码路径;

注意生成的动态链接库文件名称cJNI.so要与一开始的java代码中System.load("/home/sj/jni/test/cJNI.so");对应。

这样该路径下就有如下的五个文件了。

java源码分析-native方法的调用

2.5完成调用

完成以上操作,就可以执行我们的java代码,完成调用了:

java JNIDemo

java源码分析-native方法的调用

通过执行打印的结果hello jni! success !可以看出,java调用到了native方法,并执行了C文件中的方法体,并打印出执行成功。

简单总结一下JNI的调用过程:

第一,通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存;

第二,当Java程序需要调用本地方法时,虚拟机在加载的动态文件中定位并链接该本地方法,从而得以执行本地方法。

3.JNI的使用场景

3.1解决性能问题

当程序对时间或者性能要求特别高时,就可能需要使用底层语言,例如使用C或者C++来执行相关功能,这时候就可以通过使用java语言来调用C/C++来完成个需求了。

3.2本地方法调用问题

​ JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。

3.3嵌入式开发

​ 正是由于JNI解决了本机平台接口调用问题,于是JNI在嵌入式开发领域也是如火如荼。

3.小结

​ JNI计数可以帮助我们解决跨语言调用问题,主要解决java语言调用C/C++语言的过程。

本文地址:https://blog.csdn.net/m0_37258694/article/details/113528815

相关标签: jdk源码分析 jdk