java jni技术_JNI技术详解,让程序有飞一般的感觉

一.前言

如果你对程序的性能要求比较高,或者觉得java的运行速度已经满足不了你,底层也可以采用C++来完成,使用JNI技术直接调用,会让你的程序有飞一般的感觉。前段时间做了调研,踩了几个坑,这里总结下,希望大家少走弯路。

本文分别在windows环境和linux环境下介绍如何实现该技术。

使用工具:

1.JAVA使用的IDE为eclipse

2.windows环境下C++使用的IDE为visual studio 2010

3.linux环境下C++使用的编译器为gcc/g++

二.windows环境下java调用C++代码

2.1新建java工程,生成相应头文件

eclipse新建工程名为"jniDemo"的java工程,在包名为com.woniu.Native下新建"NativeCpp.java"类,如下:package com.woniu.Native;

public class NativeCpp {

public native void fun1();

public native int fun2(int a, int b);

public native void fun3(String url1, String url2);

}

720a990f0b91a7a498584d7a0f9007b9.png

编译生成.class文件

进入工程下的target\classes目录下,执行"javah -jni com.woniu.Native.NativeCpp",运行结果如下:

f6fbadd88ff8f47895d9f3a3d14a10a2.png

此时,会在classes目录下生成"com_woniu_Native_NativeCpp.h"头文件,头文件内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class com_woniu_Native_NativeCpp */

#ifndef _Included_com_woniu_Native_NativeCpp

#define _Included_com_woniu_Native_NativeCpp

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: com_woniu_Native_NativeCpp

* Method: fun1

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1

(JNIEnv *, jobject);

/*

* Class: com_woniu_Native_NativeCpp

* Method: fun2

* Signature: (II)I

*/

JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2

(JNIEnv *, jobject, jint, jint);

/*

* Class: com_woniu_Native_NativeCpp

* Method: fun3

* Signature: (Ljava/lang/String;Ljava/lang/String;)V

*/

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3

(JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus

}

#endif

#endif

2.2 c++生成动态库

vs2010新建工程名为"JniDll"的win32控制台应用程序,win32应用程序向导界面选择 "DLL"

857405ba0a40fc3d2f741c8e02ae0715.png

创建完成后,把2.1中生成的"com_woniu_Native_NativeCpp.h"头文件放入该工程,并把头文件中的#include 改为 "jni.h",

把JDK下include文件夹下的"jni.h"和include下win32文件夹下的"jni_md.h"头文件也一同放入创建的工程中。

工程目录如下:

03a49cd682d37b2f7be87ae6c534d307.png

编辑JniDll.cpp源码文件,实现头文件中的函数,如下:/********************************************************

Copyright (C), 2016-2017,

FileName: jni

Author: woniu201

Email: wangpengfei.201@163.com

Created: 2017/09/20

Description:Jni function

********************************************************/

#include "stdafx.h"

#include "com_woniu_Native_NativeCpp.h"

#include "stdio.h"

#include "stdlib.h"

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1

(JNIEnv *, jobject)

{

printf("hello world\n");

}

JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2

(JNIEnv *, jobject, jint a, jint b)

{

return a + b;

}

char* jstringToChar(JNIEnv* env, jstring jstr) {

char* rtn = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("GB2312");

jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);

jsize alen = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (alen > 0) {

rtn = (char*) malloc(alen + 1);

memcpy(rtn, ba, alen);

rtn[alen] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return rtn;

}

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3

(JNIEnv *env, jobject, jstring url1, jstring url2)

{

//jstringתchar*

char* pUrl1 = jstringToChar(env, url1);

char* pUrl2 = jstringToChar(env, url2);

printf("url1 = %s\n", pUrl1);

printf("url2 = %s\n", pUrl2);

}

我本机是64位系统,使用的是64位JDK,这里生成的动态库也要生成64位的库,否则调用的时候报如下错误:

ea47ad15ae15ac30ae1c08633163c2fa.png

更改vs编译生成64位dll,步骤如下:

cf8df945a614a9770d861d037e538ada.png

bd8430d8f2a54ef747c7cc631f620336.png

cdca101894b4f5911a9f74f514aca5a7.png

编译生成解决方案,这时候会在工程根目录下,生成"x64文件夹",Debug文件夹下会有动态库"JniDll.dll"

bc2b2aa4cfc53689cadc5c6c142ef22d.png

2.3 java调用dllpackage com.woniu.jniDemo;

import com.woniu.Native.NativeCpp;

public class App

{

public static void main( String[] args )

{

System.load("D:\\VS2010\\VC\\JniDll\\x64\\Debug\\JniDll.dll");

NativeCpp nativeCpp = new NativeCpp();

nativeCpp.fun1();

System.out.println(nativeCpp.fun2(3, 3));

nativeCpp.fun3("www.baidu.com", "www.haoservice.cn");

}

}

运行结果如下:

29bce86764859f69fdf043ac4a38c773.png

三.linux(CentOS)环境下java调用C++代码

3.1 编译环境

a.安装gcc和g++

yum install gcc-c++

b.安装jdk

去官网上下载jdk安装包,建议使用rpm安装包,会自动配置环境变量。安装完后如下:

1d8c183e372a0aaa92f1df79e29fe1ea.png

本机的安装目录为:/usr/java/jdk1.8.0_144/,不同版本可能不同。

这里一定要注意不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件。

3.2 制作动态库(so库)

a.创建文件夹"jniso",mkdir jniso。

b.把2.1中生成的头文件"com_woniu_Native_NativeCpp.h"拷贝过来,#include "jni.h"改为#include

c.新建jni.cpp源文件,添加如下代码:#include

#include "com_woniu_Native_NativeCpp.h"

#include "stdio.h"

#include "stdlib.h"

#include "string.h"

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun1 (JNIEnv *, jobject)

{

printf("hello world\n");

}

JNIEXPORT jint JNICALL Java_com_woniu_Native_NativeCpp_fun2

(JNIEnv *, jobject, jint a, jint b)

{

return a + b;

}

char* jstringToChar(JNIEnv* env, jstring jstr) {

char* rtn = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("GB2312");

jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);

jsize alen = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (alen > 0) {

rtn = (char*) malloc(alen + 1);

memcpy(rtn, ba, alen);

rtn[alen] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return rtn;

}

JNIEXPORT void JNICALL Java_com_woniu_Native_NativeCpp_fun3

(JNIEnv *env, jobject, jstring url1, jstring url2)

{

char* pUrl1 = jstringToChar(env, url1);

char* pUrl2 = jstringToChar(env, url2);

printf("url1 = %s\n", pUrl1);

printf("url2 = %s\n", pUrl2);

}

d.编译,生成动态库

g++ -fPIC -c jni.cpp -I /usr/java/jdk1.8.0_144/include/ -I /usr/java/jdk1.8.0_144/include/linux/

g++ -shared jni.o -o jni.so

3.3 java调用jni.soimport com.woniu.Native.NativeCpp;

public class App

{

public static void main( String[] args )

{

//windows环境下加载库

//System.load("D:\\VS2010\\VC\\JniDll\\x64\\Debug\\JniDll.dll");

//linux下加载库

System.load("/mnt/hgfs/svn/svn/Demo/jniso/jni.so");

NativeCpp nativeCpp = new NativeCpp();

nativeCpp.fun1();

System.out.println(nativeCpp.fun2(3, 3));

nativeCpp.fun3("www.baidu.com", "www.haoservice.cn");

}

}

运行结果如下:

cbfa5dbf59eb3bfa7346b0d7bb72288c.png

往期推荐

【技术篇】

【技术篇】

【生活篇】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值