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

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字节码文件:
在这里插入图片描述

2.3javah命令

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

javah JNIDemo

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXOqDt4w-1612182247998)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210201190624806.png)]

可以看一下这个文件,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");对应。

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-16Dp61Du-1612182248001)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210128213052269.png)]

2.5完成调用

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

java JNIDemo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yS4YUNc7-1612182248005)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210201192209791.png)]

通过执行打印的结果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++语言的过程。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值