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文件:
可以看一下这个文件,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");对应。
这样该路径下就有如下的五个文件了。
2.5完成调用
完成以上操作,就可以执行我们的java代码,完成调用了:
java JNIDemo
通过执行打印的结果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
上一篇: C# WPF 自定义按钮的方法
下一篇: CSS选择器的用法(详解)
推荐阅读
-
Java记录 -88- 利用反射机制调用对象的私有方法和属性
-
使用java反射,获取类的私有属性,调用类的私有方法
-
关于java的反射,调用私有方法(有参数私有方法),私有属性
-
Java通过反射调用其他类的私有属性和私有方法
-
通过JAVA的反射调用类中的公有私有方法
-
PHP5 在调用 JAVA WebService 时遇到的各种问题解决方法_PHP教程
-
JS Cookie路径问题分析:发现在不同的目录下,调用同一个js方法来存储Cookie,到别的目录取不出或取出的值是不对的
-
Java调用Oracle存储过程传入数组参数的方法
-
PHP调用java类的两种方法_PHP教程
-
PHP调用存储过程返回值不一致问题的解决方法分析,存储过程不一致_PHP教程