ubuntu下Java通过JNI调用C

本文介绍如何使用JNI让Java程序调用C语言编写的函数,包括生成JNI头文件、编写C代码、编译生成动态链接库及在Java中加载使用的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

下面看一个实例,如下:

public class TestJNI {
	static {
		System.loadLibrary("diaoyong"); // 程序在加载时,自动加载libdiaoyong.so库
	}

	public native void set(int value); // 声明原生函数。注意要添加native关键字

	public native int get();

	public static void main(String[] args) {
		TestJNI test = new TestJNI();
		test.set(1);
		System.out.println(test.get());
	}
}

 

javac  TestJNI.java命令生成java.class文件

javah -jni TestJNI命令生成TestJNI.h文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestJNI */

#ifndef _Included_TestJNI
#define _Included_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     TestJNI
 * Method:    set
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_TestJNI_set
  (JNIEnv *, jobject, jint);

/*
 * Class:     TestJNI
 * Method:    get
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_TestJNI_get
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。

jint是以JNI为中介使Java的int类型与本地的int沟通的一种类型。

JavaC/C++字节数
booleanjboolean1
bytejbyte1
charjchar2
shortjshort2
intjint4
longjlong8
floatjfloat4
doublejdouble8

对于数组型参数,

JavaC/C++
boolean[ ]JbooleanArray
byte[ ]JbyteArray
char[ ]JcharArray
short[ ]JshortArray
int[ ]JintArray
long[ ]JlongArray
float[ ]JfloatArray
double[ ]JdoubleArray

函数的名称是Java_+Java程序的package路径+函数名组成的。

Dynamic linkers resolve entries based on their names. A native method name is concatenated from the following components:

  • the prefix Java_
  • a mangled fully-qualified class name
  • an underscore (“_”) separator
  • a mangled method name
  • for overloaded native methods, two underscores (“__”) followed by the mangled argument signature

对于本地方法参数来说

函数的名称是Java_+Java程序的package路径+函数名组成的。

 

第一个参数JNIEnv接口指针,指向一个个函数表,函数表中的每一个入口指向一个JNI函数。本地方法经常通过这些函数来访问JVM中的数据结构。下图演示了JNIEnv这个指针:

第二个参数根据本地方法是一个静态方法还是实例方法而有所不同。本地方法是一个静态方法时,第二个参数代表本地方法所在的类;本地方法是一个实例方法时,第二个参数代表本地方法所在的对象。如上例子当Java_TestJNI_get与Java_TestJNI_set是一个实例方法,因此jobject参数指向方法所在的对象。

 

继续编写对应的c语言的实现,如下:

#include <stdio.h> 

#include "TestJNI.h" 

int i=0; 

JNIEXPORT void JNICALL Java_TestJNI_set (JNIEnv * env, jobject obj, jint j) { 
   i=j*888; 
}


JNIEXPORT jint JNICALL Java_TestJNI_get (JNIEnv * env, jobject obj){
  printf("ok!You have successfully passed the Java call c\n");
  return i; 
}  

gcc -Wall -fPIC -c TestJNI.c -I ./ -I /home/mazhi/workspace/jdk1.8.0_192/include/linux/ -I /home/mazhi/workspace/jdk1.8.0_192/include/ 命令生成TestJNI.o文件。

命令中-Wall:打开警告开关。-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

 

gcc -Wall -rdynamic -shared -o libdiaoyong.so TestJNI.o

动态链接库的名字必须是 lib*.so,因为编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称。这里是libdiaoyong.so对应于Java程序里的diaoyong) 选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中。-shared指编译后会链接成共享对象。

 

编译~/.bashrc文件,添加环境变量的配置export LD_LIBRARY_PATH=./ 使用source ~/.bashrc命令使配置生效

java TestJNI对文件进行运行即可。

 

参考文章:

(1)Java通过-jni调用c语言 https://jingyan.baidu.com/album/6c67b1d68e33bc2787bb1ee6.html?picindex=3

(2)HotSpotVM JNI实现浅析 https://yq.aliyun.com/articles/20284

(3)JNI规范 https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html

 

 

 

转载于:https://www.cnblogs.com/mazhimazhi/p/11330528.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值