windows和linux环境下java调用C++代码-JNI技术

标签: jni java调c++
2660人阅读 评论(8) 收藏 举报
分类:

一.前言


最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(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);
}



编译生成.class文件

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



此时,会在classes目录下生成"com_woniu_Native_NativeCpp.h"头文件,头文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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"



创建完成后,把2.1中生成的"com_woniu_Native_NativeCpp.h"头文件放入该工程,并把头文件中的#include <jni.h>改为 "jni.h",
把JDK下include文件夹下的"jni.h"和include下win32文件夹下的"jni_md.h"头文件也一同放入创建的工程中。

工程目录如下:



编辑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位的库,否则调用的时候报如下错误:



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






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



2.3 java调用dll

package 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");
    }
}

运行结果如下:




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


3.1 编译环境

a.安装gcc和g++
  yum install gcc-c++

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

  本机的安装目录为:/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 <jni.h>

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

#include <jni.h>
#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.so

import 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");
    }
}

运行结果如下:




windows下生成dll源码地址:点击打开链接

linux下生成so动态库源码地址:点击打开链接

更多技术文章请关注微信公众号“Java架构师之路”:

查看评论

如何使用JNA调用本地C/C++动态链接库详细示例代码

  • 2011年07月22日 15:24
  • 1.02MB
  • 下载

JNA实战笔记汇总<二> JNA和C/C++的数据类型转换

简介先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可。首先看下JNI...
  • abc6368765
  • abc6368765
  • 2017-09-04 21:15:46
  • 1958

JNI实现Java调用C++程序(Linux 64位)

简介使用Java通过JNI方式调用C++动态库文件 gcc 4.8.5 centos7 jdk 1.8.0生成C++头文件写一个native方法,testString,作为Java程序中调用的函...
  • Wang_Xin_SH
  • Wang_Xin_SH
  • 2017-09-03 10:19:56
  • 1305

Java在linux下调用C/C++生成的so文件

转载自:http://blog.csdn.net/undoner/article/details/50738051 1. CplusUtil.java是java web工程中的一个工具类 内容如...
  • u012377333
  • u012377333
  • 2016-02-27 15:23:03
  • 3364

java调用c/c++代码

JNI是Java Native Interface的英文缩写, 中文翻译为本地调用, 自从Java 1.1开始就成为了Java标准的一部分。 C/C++是系统级的编程语言, 可以用来开发任何和系统相关...
  • jshayzf
  • jshayzf
  • 2014-01-26 11:15:58
  • 9468

在java中调用c/c++代码的方法(jni)

在java中调用c/c++可以通过jni实现。jni(java native interface)是java语言与其它语言进行交互的标准。java中实现调用c/c++代码的方式如下: 1、编写带nat...
  • T_Ren1988
  • T_Ren1988
  • 2013-10-26 19:02:10
  • 5011

Windows下使用Java Jni调用C/C++初探

一、Java本地方法原理详解《Java核心技术 卷II 高级特性》第十二章 本地方法 原理可以用书中的这幅图来描述: 二、 使用工具Visual Studio 2010,Eclipse...
  • pxhero2012
  • pxhero2012
  • 2016-10-25 19:07:22
  • 2447

linux下 使用JNI 来以C++调用JAVA的类!(一)

           决定使用JNI,实际是为了能够将通讯与调用后台的lucene索引,因此老大决定要采用这种方式来实现index的多机分布式的索引服务。接到任务,使用C++来调用Lucene的jav...
  • doomhuntercj
  • doomhuntercj
  • 2007-04-20 15:13:00
  • 4394

java jni 入门1 - 一个简单的从Java程序中调用C函数

参考:《JAVA核心技术 卷II:高级特性》第12章 本地方法 ######################################################3 使用本地代码...
  • u012005313
  • u012005313
  • 2015-11-08 15:46:14
  • 5745

JAVA JNI 调用C/C++库提高运行效率 (图)

JAVA JNI 调用C/C++库提高运行效率    JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的...
  • sdnasky
  • sdnasky
  • 2006-11-19 16:41:00
  • 5124
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 36万+
    积分: 3248
    排名: 1万+
    站长统计
    站长统计
    博客专栏
    最新评论