java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > JAVA中调用C语言函数

JAVA中调用C语言函数的实现方式

作者:猪哥-嵌入式

这篇文章主要介绍了JAVA中调用C语言函数的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景知识

本地代码

在JAVA中使用其他语言的代码(如C/C++)称为本地代码。

历史原因

JAVA的早期阶段,很多人认为使用C和C++来加速JAVA应用中的关键部分是个好主意,但是实际上,虽然JAVA的代码确实没有纯C的运行快,但是JAVA平台实现要更快,也更稳定。

本地代码的应用场景

本地代码,比如C,对于跨平台需求,需要针对支持的平台提供单独的本地类库,而且使用C/C++编写的代码没有对通过使用无效指针所造成的内存腹泻提供任何包含,比如内存回收等,所以会容易破坏程序。

因此,只有在必要的时候才使用本地代码,如下三种场景:

JNI

JNI是Java Native Interface的缩写,JNI是JAVA平台专门用于和本地C代码进行相互操作的API,称为JAVA本地接口。

JNI开发流程

JNI头文件规则

在JAVA中,调用本地代码,需要实现本地代码,需要编写一个相应的C函数,而C函数需要按照JAVA虚拟机的规则来实现,其规则如下:

示例

本例中,通过简单的打印功能C函数来举例,在C中使用printf来实现某个打印函数,在JAVA中调用该功能函数。

1. 使用native创建一个本地方法

JAVA中使用关键字native表示本地方法,在JAVA类中声明一个方法,我们先创建一个HelloNative类,

代码如下:

public class HelloNative {
    public static native void greeting();
}

2. 使用javac -h生成头文件

使用 -h 标志运行javac (java 编译工具),提供头文件存放目录,实现对应头文件的生成。

命令代码如下:

javac -h ./ HelloNative.java

运行上述命令后,就会在./ (当前目录)下自动生成一个名为 HelloNative.h的头文件,

头文件内容如下:

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

其中JNIEXPORT和JNICALL为宏定义,在头文件jni.h中定义,jni.h在JDK安装包中已经包含。

他们的作用是为自动装在库的导出函数表明了依赖于编译器的说明符。

3. 编写本地方法的C代码

我们需要根据头文件中本地方法的声明原型,使用C实现,

程序如下:

#include <stdio.h>
#include "HelloNative.h"
JNIEXPORT void JNICALL Java_HelloNative_greeting(JNIEnv *env, jclass cl)
{
    printf("this is hello native .c printf\n");
}

上述代码中,include了步骤2生成的头文件,另外补充了JNIEnv和jclass,默认的参数。

4. 在linux下,编写该C代码的动态库

需要说明的是,由于该C代码引用了jdk中的 jni.h头文件,所以生成动态库时,需要引用JDK的头文件位置,

命令码如下:

gcc -fPIC -I/opt/ctools/jdk1.8.0_301/include/ -I/opt/ctools/jdk1.8.0_301/include/linux/ -shared -o libHelloNative.so HelloNative.c

其中/opt/ctools/jdk1.8.0_301/include/ 和 /opt/ctools/jdk1.8.0_301/include/linux为依赖jdk的头文件目录。

编译生成了 libHelloNative.so 共享库。

5. 在JAVA程序中加载步骤5中生成的类库,执行

在JAVA程序中,通过System.loadLibrary方法调用动态库,我们再编写一个HelloNativeTest测试类,

代码如下:

public class HelloNativeTest {
	public static void main(String[] args)
	{
		HelloNative.greeting();
	}
	static
	{
		System.loadLibrary("HelloNative");
	}
}

使用javac 编译该测试类

javac HelloNativeTest.java

将步骤4中生成的动态库添加到库路径中,命令如下:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

编译生成HelloNativeTest.class 字节码, 使用java命令执行

java HelloNativeTest

执行命令结果如下:

this is hello native .c printf

至此就实现了在JAVA中调用C本地代码的完整示例。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文