博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java学习记录之JNI相关
阅读量:4048 次
发布时间:2019-05-25

本文共 6280 字,大约阅读时间需要 20 分钟。

文章目录

java调用c语言主要通过下面这三个步骤来实现的

  1. 加载c库
  2. 找到对应的c函数,有对应的映射规则
  3. 调用函数

在这里插入图片描述

实际的例子

  1. TestJni.java 文件
  2. testJni.c 文件

TestJni.java 源代码

public class TestJni {
static {
//1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public static void main (String args[]) {
// 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数 test_demo(); }}

在java中调用 c 语言中的 test_demo 函数,有两种方式

  1. native static 声明
    public native static void test_demo();
    不加native 编译会报错
TestJni.java:7: error: missing method body, or declare abstract        public static void test_demo();                           ^1 error
public class TestJni {
static {
//1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public native static void test_demo(); public static void main (String args[]) {
// 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数 test_demo(); }}
  1. 如果不加 static 不能直接直接调用,需要使用 —》类.test_demo() 来调用
public class TestJni {
static {
//1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public native void test_demo(); public static void main (String args[]) {
TestJni t = new TestJni(); // 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数,如果加了static,直接使用test_demo()即可调用 t.test_demo(); }}

testJni.c 源代码

#inlcude 
void test_demo(){
printf("func:%s, line:%d\n", __func__, __LINE__);}int main() {
return 0;}

那么怎么调用呢?

jni.pdf–>chapter 2 Getting Started

编译java代码的命令

javac -encoding gbk TestJni.java

生成c里面对应的头文件

javah -jni TestJni

会在目录下面生成一个TestJni.h

这里会写c语言中函数名称应该写成什么样,其实是 类名+函数名

sgy@ubuntu:~/sgy/java_learn/jni_learn$ cat TestJni.cat: TestJni.: No such file or directorysgy@ubuntu:~/sgy/java_learn/jni_learn$ cat TestJni.h/* DO NOT EDIT THIS FILE - it is machine generated */#include 
/* Header for class TestJni */#ifndef _Included_TestJni#define _Included_TestJni#ifdef __cplusplusextern "C" {
#endif/* * Class: TestJni * Method: test_demo * Signature: ()V */JNIEXPORT void JNICALL Java_TestJni_test_1demo (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endifsgy@ubuntu:~/sgy/java_learn/jni_learn$

修改testJni.c文件

#include 
#include
#include "TestJni.h"JNIEXPORT void JNICALLJava_TestJni_test_1demo(JNIEnv *env, jobject obj){
printf("func:%s, line:%d\n", __func__, __LINE__);return;}int main() {
return 0;}

编译成动态库

gcc -fPIC -shared -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux/ -o libtestJni.so testJni.c

告诉java 动态库的路径,需要设置环境变量

export LD_LIBRARY_PATH=.

运行java的命令

java TestJni

第二种方法, testJni.c 源码

第一种方法,c语言的函数的名字比较固定,第二种可以比较方便的指定对应关系

jni.pdf—>8.4.1 The JNI_OnLoad Handler

在这里插入图片描述

void test(){
printf("func:%s, line:%d\n", __func__, __LINE__);}static const JNINativeMethod methods[] = {
{
"test_demo", "()V", test}, };JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){
JNIEnv *env; jclass cls; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
return JNI_ERR; /* JNI version not supported */ } cls = (*env)->FindClass(env, "TestJni"); if (cls == NULL) {
return JNI_ERR; } if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) {
return JNI_ERR; } return JNI_VERSION_1_4;}
  1. cls = (*env)->FindClass(env, “JNIDemo”); 先要找到对应的类,返回一个cls
  2. (*env)->RegisterNatives(env, cls, methods, 1) 注册对应java函数和c函数的对应关系,对应关系存在methods结构体里面
typedef struct {
char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */} JNINativeMethod;static const JNINativeMethod methods[] = {
{
"test_demo", "()V", test}, };

最后的源代码

#include 
#include
#include "TestJni.h"JNIEXPORT void JNICALLJava_TestJni_test_1demo(JNIEnv *env, jobject obj){
printf("func:%s, line:%d\n", __func__, __LINE__); return;}void test(){
printf("func:%s, line:%d\n", __func__, __LINE__);}static const JNINativeMethod methods[] = {
{
"test_demo", "()V", test}, };JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){
JNIEnv *env; jclass cls; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
return JNI_ERR; /* JNI version not supported */ } cls = (*env)->FindClass(env, "TestJni"); if (cls == NULL) {
return JNI_ERR; } if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) {
return JNI_ERR; } return JNI_VERSION_1_4;}int main() {
return 0;}

signature的格式和介绍

在这里插入图片描述
jni的字段描述符
对于参数是String类, signature应该写成 Ljava/lang/String;
对于其他类,统一写成 Ljava/lang/Object;

java函数怎么传递参数到c函数里面

1. 基本数据类型,直接使用,直接返回

TestJni.java 里面的函数改成下面这个样子

public native static int test_demo(int java_var);		System.out.println(test_demo(1));

testJni.c

jint test(JNIEnv *env, jclass cls, jint java_var){
printf("func:%s, line:%d, java_var:%d\n", __func__, __LINE__, java_var); return 2;}

执行结果

func:test, line:13, java_var:12

2. String类型参数,返回值是String类型

jni.pdf—>P39

TestJni.java 里面的函数改成下面这个样子

public native static String test_demo(String java_str);	System.out.println(test_demo("java_str"));

testJni.c

jstring test(JNIEnv *env, jclass cls, jstring java_str){
const jbyte *str; str = (*env)->GetStringUTFChars(env, java_str, NULL); if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */ } printf("func:%s, line:%d, java_str:%s\n", __func__, __LINE__, str); return (*env)->NewStringUTF(env, "c_str");;}static const JNINativeMethod methods[] = {
{
"test_demo", "(Ljava/lang/String;)Ljava/lang/String;", test}, };

执行结果

func:test, line:20, java_str:java_strc_str

3. 数组类型参数,返回值是int类型

jni.pdf—>P49

TestJni.java 里面的函数改成下面这个样子

public native static int test_demo(int array[]);		int array[] = {
1, 2, 3}; System.out.println(test_demo(array));

testJni.c

jint test(JNIEnv *env, jclass cls, jintArray java_array){
jint i = 0; jint sum = 0; jint *cArray; cArray = (*env)->GetIntArrayElements(env, java_array, NULL); if (cArray == NULL) {
return 0; /* exception occurred */ } for (i = 0; i < (*env)->GetArrayLength(env, java_array); i++) {
sum += cArray[i]; } (*env)->ReleaseIntArrayElements(env, java_array, cArray, 0); return sum;}static const JNINativeMethod methods[] = {
{
"test_demo", "([I)I", test}, };

执行结果

6

jni关于数组提供的一些函数接口

在这里插入图片描述

PS:疑问

  1. 如果jni的字段描述符 java函数和C语言函数不匹配执行的时候会有什么效果?
         执行的时候会报错
Exception in thread "main" java.lang.NoSuchMethodError: Method TestJni.test_demo()V name or signature does not match

转载地址:http://ihyci.baihongyu.com/

你可能感兴趣的文章
网络视频服务器移植
查看>>
Encoding Schemes
查看>>
移植QT
查看>>
如此调用
查看>>
计算机的发展史
查看>>
带WiringPi库的交叉编译如何处理一
查看>>
带WiringPi库的交叉笔译如何处理二之软链接概念
查看>>
Spring事务的七种传播行为
查看>>
ES写入找不到主节点问题排查
查看>>
Java8 HashMap集合解析
查看>>
欢迎使用CSDN-markdown编辑器
查看>>
Android计算器实现源码分析
查看>>
Android系统构架
查看>>
Android 跨应用程序访问窗口知识点总结
查看>>
各种排序算法的分析及java实现
查看>>
SSH框架总结(框架分析+环境搭建+实例源码下载)
查看>>
自定义 select 下拉框 多选插件
查看>>
js获取url链接携带的参数值
查看>>
gdb 调试core dump
查看>>
gdb debug tips
查看>>