JNI开发:入门篇

前言

我们知道Java是一种编译解释型语言,编译后得到.class文件再经由jvm解释执行,尽管jvm现在已经相当高效,但和C/C++这种可以直接编译为可执行文件的语言相比效率还是略逊一筹。为了让Java更加高效也为了跨平台能力,JNI(Java Native Interface)应运而生。

JNI简单来说就是让Java方法中可以调用C函数,C函数也可以调用Java。这样做的好处有很多:在计算密集型场景适当使用jni可以显著提高效率;需要直接操作内存时JNI更加合适,例如Object类中的clone()方法;本地链接库不易破解,核心算法和一些加/解密操作可以放在本地方法中。

下面我会写一个小示例,用到的工具和环境如下:

1. 在Java文件定义本地方法并生成头文件

package com.leqi.example;

public class Hello {

    public static native String helloFromNative();

    public static void main(String[] args) {
        System.out.println(helloFromNative());
    }
}

IDEA新建一个类Hello,定义一个native方法helloFromNative(),方法返回一个String类。

如果你是Kotlin爱好者,可以这么写,新建Koltin File(名字随便起):

@file:JvmName("Hello")
package com.leqi.example

external fun helloFromNative(): String

fun main() {
    System.load("C:\\Users\\LG\\Desktop\\libNativeHello.dll")
    println(helloFromNative())
}

Kotlin和Java并无本质上的区别,只是要注意Kotlin File编译后文件名会发生改变,只需要指定JvmName用起来就差不多了。

点击IDEA的绿色小锤子编译项目,然后在这个目录下找到编译后的.class文件。

随后打开命令行工具,cd到项目文件夹名\out\production\项目文件夹名下,输入命令javah com.leqi.example.Hello,不指定输出目录的话头文件会自动生成在当前目录下。

如果jdk版本高,javah命令被移除的话可以用javac -h命令代替。用命令行生成只是为了省事,后期熟练了自己手写头文件也是没关系的。

2. 编译动态链接库

打开Clion新建C++Library项目,Library type选择shared。

第一次新建项目时如果没有配置编译工具的话点击file - setting中,找到Toolchains然后添加MinGW,把MinGW的根目录选中即可。

接下来把上一步得到的头文件copy到项目中,再找到jdk安装目录,在include目录下找到jni.h文件,include/win32目录下找到jni_md.h,这两个文件也copy到项目中。

新建Hello.cpp,代码如下:

#include "com_leqi_example_Hello.h"
#include "string"

extern "C" {

JNIEXPORT jstring
JNICALL Java_com_leqi_example_Hello_helloFromNative
        (JNIEnv *env, jclass) {
    std::string hello = "Hello World from C++";
    return env->NewStringUTF(hello.c_str());
}
}

extern "C"很重要,它的功能是让编译器以处理 C 语言代码的方式处理C++代码,否则jni调用时会出现问题。

JNI函数命名是有一些规则的,并不是我们想怎么写就怎么写,首先是JNIEXPORT表明这还是个可被外部调用的函数。

接下来是函数的返回值jstring,这个东西可以展开讲讲,我们知道Java和C是两套东西,它们的基本数据类型是不可以直接互相调用的,所以jni头文件中就定义了各种各样的映射,我在别人博客盗了个表格:

Java类型 本地类型 描述
boolean jboolean C/C++8位整型
byte jbyte C/C++带符号的8位整型
char jchar C/C++无符号的16位整型
short jshort C/C++带符号的16位整型
int jint C/C++带符号的32位整型
long jlong C/C++带符号的64位整型e
float jfloat C/C++32位浮点型
double jdouble C/C++64位浮点型
Object jobject 任何Java对象,或者没有对应java类型的对象
Class jclass Class对象
String jstring 字符串对象
Object[] jobjectArray 任何对象的数组
boolean[] jbooleanArray 布尔型数组
byte[] jbyteArray 比特型数组
char[] jcharArray 字符型数组
short[] jshortArray 短整型数组
int[] jintArray 整型数组
long[] jlongArray 长整型数组
float[] jfloatArray 浮点型数组
double[] jdoubleArray 双浮点型数组

JNICALL表明这个函数是个jni函数,jni函数名的命名也是有规则的,Java_Java包名_Java类名_native函数名,函数都会有两个固定的参数JNIEnv *env, jclass是由jvm虚拟机传入的,env指针提供了大量的访问java变量和方法的函数,后面会常用到。

接下来修改CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.17)
project(NativeHello)

set(CMAKE_CXX_STANDARD 14)

add_library(NativeHello SHARED com_leqi_example_Hello.h Hello.cpp)

其实CMakeLists也很容易理解,主要把你要编译的文件名写在add_library中的SHARED后面即可。

最后点击绿色的小锤子编译一下项目,然后可以看到libNativeHello.dll文件,这个就是我们要的C函数库,现在把它copy到桌面或者容易找的地方。

3. Java中调用C函数库

回到IDEA,在Hello.java中略作修改:

package com.leqi.example;

public class Hello {

    public static native String helloFromNative();

    public static void main(String[] args) {
        System.load("刚才编译好的.dll文件的绝对路径");
        System.out.println(helloFromNative());
    }
}

运行看一下结果


OK,大功告成,接下来我会写一篇C和Java之间传递复杂数据类型的文章。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容