JNI

一、JNI书写步骤

JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java 虚拟机环境。

1.1 编写Java程序

public class TestJNI{
	//所有native关键词修饰的都是对本地的声明
    public native void get(); 
}

1.2 编译Java程序

javac TestJNI.java

1.3 生成扩展名为h的头文件

javah命令用于生成头文件。新版jdk-10.0.2已经移除了javah命令工具,使用javac HelloWorld.java -h JniH 代替javah HelloWorld 命令生成扩展名为h的头文件。

在下面这行命令中.表示头文件生成的位置,mine.TestJNI表示java的类路径
注意:我们执行javah一定要在mine(根据自己的java文件位置决定)的父级别目录下.

javah -classpath . -jni mine.TestJNI

在这里插入图片描述
在这里插入图片描述
头文件内容:

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

#ifndef _Included_mine_TestJNI
#define _Included_mine_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     mine_TestJNI
 * Method:    get
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mine_TestJNI_get
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

1.4 编写本地方法

创建后缀为.c.cpp的文件,实现头文件里面的方法,这里我使用的工具是JetBrains CLion 2019.2 x64:

第一步:

创建一个新的工程
在这里插入图片描述
在这里插入图片描述

第二步:

把头文件mine_TestJNI.hjni.hjni_md.h拷贝到TestJNI工程下。删除testJNI.cpp已经testJNI.h
主意:jni.h文件在你的JDK目录的include目录下,jni_md.h在include的win32目录下。
在这里插入图片描述

第三步:

创建mine_TestJNI.cpp文件实现mine_TestJNI.h头文件里面的方法。

在这里插入图片描述

mine_TestJNI.cpp文件内容:

#include "mine_TestJNI.h"
#include <iostream>
#include <stdio.h>

JNIEXPORT void JNICALL Java_mine_TestJNI_get (JNIEnv *, jobject) {
    printf("this is C++ print");
}

1.5 生成动态库

第一步编辑CMake文件:

cmake_minimum_required(VERSION 3.12)
project(TestJNI)

set(CMAKE_CXX_STANDARD 14)

add_library(TestJNI SHARED mine_TestJNI.cpp mine_TestJNI.h jni.h jni_md.h)

第二步运行生成动态库

在这里插入图片描述
在这里插入图片描述

注意:如果出现以下错误,修改对应位置的 #include <jni.h>#include "jni.h"即可。
在这里插入图片描述

1.6 运行程序

public class TestJNI {

    public native void get();

    static {
        System.load("D:\\Jumper\\upload\\libTestJNI.dll");//载入本地库
    }
    public static void main(String[] args) {
        new TestJNI().get();
    }
}
二、类型对应表
Java 类型本地 C 类型实际表示的 C 类型(Win32)说明
booleanjbooleanunsigned char无符号,8 位
bytejbytesigned char有符号,8 位
charjcharunsigned short无符号,16 位
shortjshortshort有符号,16 位
intjintlong有符号,32 位
longjlong__int64有符号,64 位
floatjfloatfloat32 位
doublejdoubledouble64 位
voidvoidN/AN/A
三、相关问题

3.1 如何将java传入的String参数转换为c的char*,然后使用

java传入的String参数,在c文件中被jni转换为jstring的数据类型,在c文件中声明char* test,然后test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);注意:test使用完后,通知虚拟机平台相关代码无需再访问:(*env)->ReleaseStringUTFChars(env, jstring, test);

JNIEXPORT void JNICAL Java_test_string(JNIEnv *env, jclass thiz, jstring str) {
	const char *test = (* env)->GetStringUTFChars(env, str,0);
	(*env)->ReleaseStringUTFChars(env, str, test); //通知JVM清除内存
}

3.2 将c中获取的一个char*转化为string

这个char*如果是一般的字符串的话,作为string传回去就可以了。如果是含有’\0’的buffer,最好作为bytearray传出,因为可以制定copy的length,如果copy到string,可能到’\0’就截断了。
有两种方式传递得到的数据:

1)方法一
一种是在jni中直接new一个byte数组,然后调用函数(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);将buffer的值copy到bytearray中,函数直接return bytearray就可以了。

JNIEXPORT jstring JNICAL Java_test_string(JNIEnv *env, jclass thiz, jstring str) {
	jbyteArray bytearray;
	bytearray = (*env)->NewByteArray(env,len);
	(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);
	return bytearray;
}

1)方法二

JNIEXPORT jstring JNICAL Java_test_string(JNIEnv *env, jclass thiz, jstring str) {
	jstring p;
	p = (* env)->NewStringUTF(env,"success");
	return p;
}

3.3 不知道占用多少空间的buffer,如何传递出去呢?

在jni的c文件中new出空间,传递出去。java的数据不初始化,指向传递出去的空间即可。

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书香水墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值