Java与C/C++互调用法(JNI调用第三方库)

使用Java调用C/C++ 文章目录前言JNI概述例子编写Java代码编译生成的class文件:JNITest.class在命令行下使用javah生成C/C++头文件。在工程的bin目录下输入以下命令:实现C++代码。在VS2008中创建一个Win32 project,类型为DLL。构建C++项目将dll文件复制到Java工程的bin目录下 前言 我们知道Java是一种平台无关性的语言,平台对于上层的java代码来说是透明的... 阅读详情

在实际应用中,经常会有下面的情况。已经给出了由C/C++编译好的第三方动态链接库.dll文件,里面封装了一些我们要用的接口,并给出了接口相关的头文件,从中我们知道这些接口的参数类型和返回值类型,以方便我们调用这些接口。在Java应用中,有时为了某种需要,我们就必须要借助C/C++的动态链接库帮助我们完成我们要做的工作。这时JNI出现了,JNI(Java Native Interface)是由SUN提供的一套标准接口,供本地应用(C/C++)与JavaVM相互调用。

接下来就通过一个具体实例讲解JNI调用第三方动态库的用法。

一、准备工作:

由于手里面没有合适的第三方动态库可供调用,就自己手动封装了一些简单的函数接口,然后编译成动态链接库。实际应用中可能会提供已存在的动态链接库。下面就首先在VC中新建一个Win32项目BasicFunc——下一步——选择.dll 空项目 完成;新建头文件BasicFunc.h和源文件BasicFunc.cpp如下:

//BasicFunc.h:

double add(double a, double b);

double multiply(double a, double b);

double max(double a, double b);

 

//BasicFunc.cpp

#include <iostream>

using namespace std;

#ifdef __cplusplus

extern "C" {

#endif

   //__declspec(dllexport) is used to force generate function name as 'add

   //so you can find the address of this function by searching in the dll

   __declspec(dllexport)double add(double a, double b)

   {

       cout<< a << "与" << b<< "的和是:" << a + b << endl;

       returna + b;

   }

   __declspec(dllexport)double multiply(double a, double b)

   {

       cout<< a << "与" << b<< "的积是:" << a * b << endl;

       returna*b;

   }

   __declspec(dllexport)double max(double a, double b)

   {

       cout<< a << "与" << b<< "中较大者是:" << (a > b ? a : b)<< endl;

       return(a> b ? a : b);

   }

#ifdef __cplusplus

}

#endif

在VC中编译即可生成名为BasicFunc.dll的动态链接库。接下来我们就演示在Java中调用BasicFunc.dll中封装的接口的方法。

 

二、为了调用BasicFunc.dll中的接口函数,需要借助JNI来实现。在JNI中通过一个中介dll调用该接口。

1) 编写一个类,声明native方法

public class CallBasicFunc {

    public native voidCallBasicFuncAdd(double a,double b);

    public native doubleCallBasicFuncMul(double a,double b);

    static{

       System.loadLibrary("BasicFuncMediumDll");

    }

}

2)编译生成.h文件

cmd到CallThirdParty.java目录下,执行以下几个命令,生成.h文件。(需要设定java环境变量)

第一步:javac  CallBasicFunc.java 生成CallBasicFunc.class

第二步:Javah –jni CallBasicFunc生成CallBasicFunc.h头文件

内容如下:

/* DO NOT EDIT THISFILE - it is machine generated */

#include <jni.h>

/* Header for classCallBasicFunc */

 

#ifndef _Included_CallBasicFunc

#define _Included_CallBasicFunc

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:    CallBasicFunc

 * Method:   CallBasicFuncAdd

 * Signature: (DD)V

 */

JNIEXPORT void JNICALL Java_CallBasicFunc_CallBasicFuncAdd

  (JNIEnv *, jobject, jdouble, jdouble);

 

/*

 * Class:    CallBasicFunc

 * Method:   CallBasicFuncMul

 * Signature: (DD)D

 */

JNIEXPORT jdouble JNICALL Java_CallBasicFunc_CallBasicFuncMul

  (JNIEnv *, jobject, jdouble, jdouble);

 

#ifdef __cplusplus

}

#endif

#endif

3)创建C/C++工程,工程名为BasicFuncMediumDll,将上一步生成的头文件复制并添加到当前工程,添加源文件CallBasicFunc.cpp,在其中实现CallBasicFuncAdd ()和CallBasicFuncMul()方法.内容如下:

#include<Windows.h>

#include<iostream>

#include"CallBasicFunc.h"

using namespace std;

 

#ifdef __cplusplus

extern "C" {

#endif

 

typedef double (*ThirdPartyFunc)(double, double);

 

JNIEXPORT void JNICALL Java_CallBasicFunc_CallBasicFuncAdd

(JNIEnv *env, jobject obj, jdouble arg_a, jdouble arg_b)

{

    HMODULE dlh = NULL;

    ThirdPartyFunc thirdPartyFunc=NULL;

    if (!(dlh = LoadLibrary(L"BasicFunc.dll")))

    {

       printf("LoadLibrary() failed: %d\n", GetLastError());

    }

 

    double a = arg_a;

    double b = arg_b;

 

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"add")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "a+b="<< (*thirdPartyFunc)(a, b) << endl;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"multiply")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "a*b="<< (*thirdPartyFunc)(a, b) << endl;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"max")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    cout << "Bigger of a and b is: " << (*thirdPartyFunc)(a, b) << endl;

    //thirdPartyFunc= NULL;

 

}

 

JNIEXPORT jdouble JNICALL Java_CallBasicFunc_CallBasicFuncMul

(JNIEnv *env, jobject obj, jdouble arg_a, jdouble arg_b)

{

    double a = arg_a;

    double b = arg_b;

    HMODULE dlh = NULL;

    ThirdPartyFunc thirdPartyFunc = NULL;

    if (!(dlh = LoadLibrary(L"BasicFunc.dll")))

    {

       printf("LoadLibrary() failed: %d\n", GetLastError());

    }

    jdouble result;

    if (!(thirdPartyFunc = (ThirdPartyFunc)GetProcAddress(dlh,"multiply")))

    {

       printf("GetProcAddress() failed: %d\n", GetLastError());

    }

    result = (*thirdPartyFunc)(a, b);

    cout << "有返回值的本地方法a*b=" << result<< endl;

    return result;

}

#ifdef __cplusplus

}

#endif

4)Build这个工程,生成BasicFuncMediumDll.dll动态链接库

5)编写测试java程序Test.java,调用以上生成的dll库。如下:

public class Test {

     public static void main(String[]args) {      

     CallBasicFunccallThirdParty = new CallBasicFunc();

    callThirdParty.CallBasicFuncAdd(10.3, 4.8);   

         //System.out.println("两数之和是:"+res);

     System.out.println("Java中调用有返回值的本地方法"+callThirdParty.CallBasicFuncMul(34.2, 5.48));

     }   

}

输出结果:

10.3与4.8的和是:15.1

a+b=15.1

10.3与4.8的积是:49.44

a*b=49.44

10.3与4.8中较大者是:10.3

Bigger of a and b is: 10.3

34.2与5.48的积是:187.416

有返回值的本地方法a*b=187.416

Java中调用有返回值的本地方法187.41600000000003

 

这里没有演示C/C++调用Java的情况,C/C++调用Java即是在本地方法中访问Java类的成员属性和成员方法。这里需要进一步的了解JNI对操作属性和方法的用法。以后再进一步研究。

注意:没有配置环境变量的情况下,需要将第三方动态库copy到C/C++工程BasicFuncMediumDll的根目录下,将BasicFuncMediumDll.dll copy到windows的System32目录或JDK的bin目录下。

由于本人也是初次接触JNI,如有不正确的地方,还望各位大牛不吝赐教,予以指正!
使用JNI技术实现JavaC/C++互调Java调C/C++ Java作为一个技术生态平台在业界得到了广泛的应用,许许多多的大型项目都是搭载在其之上。Java语言本身功能也十分强大,能实现大量的业务逻辑算法。那么,我们为什么要让JavaC/C++互调呢,直接用Java写不就完了吗?这是初学者一个很常见的疑问,下面我们来看看为什么需要这样做。     用Java调用底层的代码(不一定指是C/C++写的,虽然大部分是)主要原因有三个:     1.运行效率 阅读详情

相关推荐

JnaJni调用C/C++效率比较

前言: JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现JavaC的数据类型映射。你不再需要编写C动态链接库。当然,这也意味着,使用JNA技术比使用JNI技术调用动态...

hqy1719239337的博客 7069

meethigher-小记Java调用C++开发的动态链接库(DLL)

五一快乐吖!死肥宅正趁着五一这段时间,努力提升自己!最近使用Java拦截Windows系统中一些默认事件时,发现了一些瓶颈。我用Java操作浏览器、用Java最小化其他应用窗口,但是我发现这个操作,他都是异步的。比如,写个程序,获取当前前置窗口,给他缩小。由于它是异步的,只是给操作系统发个通知你要缩小,但是否执行完,开发者不知道。实际上由于循环过快,就成了死循环一直获取到的是当前窗口,然后一直缩小当前窗口。最后把电脑卡死了。所以经过我在C++C#JavaGo中的语言选型,以下排序分先后。

meethigher的博客 3567

android实现app通过jni调用C/C++方法

本文实现在android app中使用调用jni调用本地C/C++方法。 1.新建android工程 2.新建java上层方法 本例子在工程中新建 cn.landsem.jnistudy 包,在其中新建TestManager类用于调用本地C/C++方法,该类的代码如下: package cn.landsem.jnistudy; import android.util.Log; pub

三言两语 1万+

使用JNI 调用第三方c++动态库

昨天晚上到今天一直在折腾这个第三方库文件,唉,要哭了,一直就是各种问题。现在详细说说怎么做,踩过哪些坑。

u014006343的专栏 7519

JavaC++如何处理循环引用问题

最近刷题刚刚研究过这个问题。 何为循环引用 如果有两个或者以上的对象,它们彼此引用,就会造成循环引用。如下面的例子 class Node { Node next ; } Node a = new Node (); Node b = new Node (); a . next = b ; b . next = a ; 代码中,a对象引用了b对象,b对象也引用了a

微小的鱼的博客 962

Java调用C++,并且C++中使用了C#的dll

在一般应用中,我们可能会经常碰到这样一种情况,提供的dll是C#的,然后我们希望封装成Java的jar包发布,而且访问这个jar包的频率非常高。 这里,我们一般可能提供两种解决方案,一种就是使用C#封装原来的C#的dll,以WebService的方式提供,然后使用Java调用这个WebService服务,最终将Java打包成jar包提供应用。另外一种方案就是先使用C++来封...

iteye_14527的博客 218

JNI—C/C++Java交互

1. 概述 在上一章节JNI—NDK开发流程(ndk-buildCMake)中讲述了NDK的开发流程,但是还遗留两个问题: C/C++ Java如何进行通信的? 如何阅读Android Native 源码? 今天来解决第二个问题C/C++Java 如何进行通信的? 2. 数据类型描述符 2.1. 数据类型 非常多博文讲述了JNI的数据类型JAVA语言数据类型的映射关系,但是为什么...

PPLLiang的博客 1951

JNI实现Java调用C/C++代码及对C/C++动态库的单步调试

JNI标准作为Java平台的一部分,提供了编译型语言进行交互的手段,尤其是对C/C++交互。如果你有一段现成的C/C++代码想在java调用,就可以通过JNI来完成。 假如有一段C代码,这段代码如下: int say_hello() { printf("Hello world!\n"); return 0; } 如果想在java中实现这段代码的调用,打印出“Hello world!“,该如何做呢?如何实现对C/C++代码实现单步调试呢? 一、新建一个java工程 我使用

zx_glave的博客 5675

探索 JNI - Rust Java 互调实战

本文从原理介绍出发,实现了 Rust Java互调。利用 JNI 技术,可以充分发挥 Rust 的性能优势,同时保持 Java 的跨平台特性。这种技术组合适用于对性能要求较高的应用场景,如图像处理、数据分析系统级编程等。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 2297

Java调用C/C++那些事(JNI

例子中,创建一个HelloWorld类。本地方法声明,表示该方法的具体实现不在Java代码中,而是在通过System.loadLibrary加载的本地库中实现。定义了四个本地方法,输入输出都是基本数据类型intstatic{定义了两个方法,一个是输入字符串,一个是输出字符串。static{定义一个对象,表示点,保存坐标x、y,提供get、set方法this.x=x;this.y=y;//get、set、toString方法省略。

weixin_42524843的博客 1635

基本JNI调用技术(c/c++java互调)

  虽不是很详细,但步骤都已相当明确了的. 一.C/C++调用Java在C/C++调用Java的方法一般分为五个步骤:初始化虚拟机、获取类、创建类对象、调用方法退出虚拟机。1. 初始化虚拟机代码如下:    JNIEnv *env;      JavaVM *jvm;     JavaVMInitArgs vm_args;     JavaVMOption op

zjsjava的专栏 6296

JNI: C/C++调用Java方法

C/C++调用Java方法步骤: FindClass: 可以在C/C++层找到Java层的类 GetMethodID/GetFieldID:得到Java层中所有的类/属性 NewObject:创建对象,这个对象就代表内存中一个Java对象。有了这个对象之后,再通过GetMethodID/GetFieldId取到的MethodID(其实它就是个索引值)/FieldID,类中这个方法/属性的索...

手写我对你的温柔 5134

Java通过JNI调用C/C++函数

在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某个体系架构或者操作系统特有功能的支持。为了能在Java 代码中调用 C/C++函数,JVM提供了Java Native Interface(JNI)机制。 在Java中,使用native关键字标注的、没有方法体的方法就是native方法。当在 Java 代码中调用这些 native 方法时,Java 虚拟机将通

weixin_54305824的博客 1178

Android NDK开发之旅(3): 详解JNI数据类型C/C++Java之间的互调

Java中有两种类型:基本数据类型(int、float、char等)引用类型(类、对象、数组等)JNI定义了一个C/C++类型的集合,集合中每一个类型对应于Java中的每一个类型,其中,对于基本类型而言,JNIJava之间的映射是一对一的,比如Java中的int类型直接对应于C/C++中的jint;而对引用类型的处理却是不同的,JNIJava中的对象当作一个C指针传递到本地函数中,这个指针指向JVM中的内部数据结构,而内部数据结构在内存中的存储方式是不可见的,本地代码必须通过在JNIEnv中选择适当

老蒋也疯狂 5954

使用JNI技术实现JavaC/C++互调(C/C++Java

上一篇博客里我们讲了怎样通过JNI动态链接库实现从Java调C/C++,今天我们来讲怎么在C/C++中获取Java的数据类型以及调用Java的方法。

wonghifong0223的博客 1468

在c/c++调用Java方法

JNI就是Java Native Interface,既可以实现Java调用本地库, 也可以实现C/C++调用Java代码, 从而实现了两种语言的互通,可以让我们更加灵活的使用。 通过使用JNI可以从一个侧面了解Java内部的一些实现. 本文使用的环境是 64位的win7系统 JDK 1.6.0u30 (32位) C/C++编译器是 Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86 (VC 6.0

顺其自然~专栏 8200

JNI简单使用之二:C/C++调用JAVA

上文中简单的说了一下JAVA调用C/C++的一般过程并举了几个具有代表性的小例子。本文来说一说C/C++是如何调用JAVA的,包括调用JAVA实现的类的方法,设置JAVA实现的类的成员、属性等。本文先说一下C/C++调用JAVA的一般步骤,在举几个小例子做分析说明。由于作者水平有限,难免会有错误以及说的不对、不好的地方,请不小心看到的您批评指正。 一、调用的一般步骤 a、创建虚拟机 b、获得

TECH_PRO的博客 4696
huigeisme123
博客等级 码龄11年 0粉丝 1原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值