linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)

摘要:
1、 JNI技术JNI是Java Native Interface的缩写。通过使用Java本地接口编写程序,您可以确保代码易于在不同平台上移植。SUN发布的Java本地接口(JNI)提供了一种将Java与C/C++、汇编和其他本地代码集成的解决方案。该规范使Java虚拟机中运行的Java代码能够与其他编程语言互操作,包括创建本地方法、更新Java对象、调用Java方法、引用Java类以及捕获和抛出差异

一、JNI技术
  JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植.
  SUN公司发布的Java 本地接口(JNI)提供了将Java与C/C++、汇编等本地代码集成的方案,该规范使得在 Java 虚拟机内运行的 Java 代码能够与其它编程语言互相操作,包括创建本地方法、更新Java对象、调用Java方法,引用 Java类,捕捉和抛出异常等,也允许Java代码调用 C/C++或汇编语言编写的程序和库。作为一个标准程序接口,它没有对底层 Java虚拟机的实现施加任何限制(特点:二进制兼容、效率高、功能强)

java与JNI数据类型对照表

1、基本数据类型

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第1张

 2、引用数据类型对照表

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第2张

二、Linux环境的准备(centos7)

 1、安装JDK(注意:不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件
linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第3张

 2、安装gcc和g++  ( yum install gcc-c++)

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第4张

  3、新建Java工程,在包名为com.ywb.Native下新建"NativeCpp.java"类,方法必须使用native修饰(native即 JNI java native interface)

package com.ywb.Native;

public class NativeCpp {

    public native void sayHello();

    public native int calculate(int num1, int num2);

    public native void output(String url, String newUrl);
}

 4、编译生成class文件,进入工程下的targetclasses目录下,执行"javah -jni com.ywb.Native.NativeCpp",生成"com_ywb_Native_NativeCpp.h"头文件


linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第5张

  4.1:com_ywb_Native_NativeCpp.h文件内容

#include <jni.h>
/* Header for class com_ywb_Native_NativeCpp */

#ifndef _Included_com_ywb_Native_NativeCpp
#define _Included_com_ywb_Native_NativeCpp
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ywb_Native_NativeCpp
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_ywb_Native_NativeCpp_sayHello
  (JNIEnv *, jobject);

/*
 * Class:     com_ywb_Native_NativeCpp
 * Method:    calculate
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_ywb_Native_NativeCpp_calculate
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_ywb_Native_NativeCpp
 * Method:    output
 * Signature: (Ljava/lang/String;Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ywb_Native_NativeCpp_output
  (JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

 5、创建c++源码文件( vim jni.cpp),将生成的头文件"com_ywb_Native_NativeCpp.h"拷贝过来,#include "jni.h"改为#include <jni.h>,再加上自己需要实现的c++代码逻辑
  

#include <jni.h>
/* Header for class com_ywb_Native_NativeCpp */

#ifndef _Included_com_ywb_Native_NativeCpp
#define _Included_com_ywb_Native_NativeCpp
#ifdef __cplusplus
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
extern "C" {
#endif
/*
 *  * Class:     com_ywb_Native_NativeCpp
 *   * Method:    sayHello
 *    * Signature: ()V
 *     */
JNIEXPORT void JNICALL Java_com_ywb_Native_NativeCpp_sayHello
  (JNIEnv *, jobject){
        printf("hello world
");
}

/*
 *  * Class:     com_ywb_Native_NativeCpp
 *   * Method:    calculate
 *    * Signature: (II)I
 *     */
JNIEXPORT jint JNICALL Java_com_ywb_Native_NativeCpp_calculate
  (JNIEnv *, jobject, jint num, jint newNum){
        return num + newNum;
}


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;
}
/*
 *  * Class:     com_ywb_Native_NativeCpp
 *   * Method:    output
 *    * Signature: (Ljava/lang/String;Ljava/lang/String;)V
 *     */
JNIEXPORT void JNICALL Java_com_ywb_Native_NativeCpp_output
  (JNIEnv *env, jobject, jstring url, jstring newUrl){
         char* pUrl1 = jstringToChar(env, url);
        char* pUrl2 = jstringToChar(env, newUrl);
        printf("url1 = %s
", pUrl1);
        printf("url2 = %s
", pUrl2);

}

#ifdef __cplusplus
}
#endif
#endif

6、编译生成动态库
 6.1:g++ -fPIC -c jni.cpp -I /home/admin/software/jdk1.8.0_202/include/ -I /home/admin/software/jdk1.8.0_202/include/linux/ linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第6张

 6.2:g++ -shared jni.o -o jni.so
linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第7张

  7、java调用c++动态库

package com.ywb.Native;

public class App {

    public static void main( String[] args )
    {
        //windows环境下加载库
        //System.load("D:\JniDll.dll");

        //linux下加载库
        System.load("/root/IdeaProjects/demo/target/classes/jni.so");

        NativeCpp nativeCpp = new NativeCpp();
        nativeCpp.sayHello();
        System.out.println(nativeCpp.calculate(15, 15));
        nativeCpp.output("www.baidu.com", "https://www.cnblogs.com/ywbmaster/www.haoservice.cn");
    }
}

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第8张

   注:可以将代码封装成jar包,为以后程序方便调用

 8、jni方法签名规则
  linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第9张

 可以进入Java编译后的class文件所在的目录,执行 javap -s  对应Java类的class文件,可以查看当前类下所有方法所对应的签名信息

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)第10张

1、方法例子:

public void example1(int string, float index)

对应签名:

(IF)V

2、方法例子:

public string example2(String string, int index,double d)

对应签名:

(Ljava/util/String;I;D)Ljava/util/String;

3、方法例子:

public int example3(int index, String value,int[] arr)

对应签名:

(ILjava/util/String;[I)I


 

 

免责声明:文章转载自《linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java基础(三十四)String、StringBuffer类和数据缓冲区Buffer类Firefox+Burpsuite抓包配置(可抓取https)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

.NET链接Oracle 参数绑定问题

在.NET项目中链接Oracle使用的驱动是 Oracle.ManagedDataAccess.dll ,这里下载 所遇到的问题 使用存储过程一个参数没有问题,发现两个或两个以上会有参数没传过来的现象。 最后通过排查发现是没有添加参数绑定(问题找了好长时间,刚开始还以为驱动的问题+_+)。 需要设置设置属性 BindByName = true; 下面附上 ...

Linux定时任务

1. 定时任务服务名称 crond 默认开机自动运行 自动启动 默认有系统的定时任务 2. 定时任务的相关文件 两个 用户的定时任务文件 /var/spool/cron/用户名 # 普通用户定义定时任务的配置文件 管理员的定时任务文件 /etc/crontab 3. 定时任务书写方式 格式 使用的/etc/crontab 管理员定时任务...

springboot elasticsearch 集成注意事项

  文章来源: http://www.cnblogs.com/guozp/p/8686904.html 一 elasticsearch基础    这里假设各位已经简单了解过elasticsearch,并不对es进入更多的,更深层次的解释,如有必要,会在写文章专门进行es讲解。   Elasticsearch是一个基于Apache Lucene(TM)的开源...

JAVA对象克隆

   1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 2> 在派生类中覆盖基类的clone(),并声明为public。3> 在派生类的clone()方法中,调用super.clone()。4> 在派生类中实现Cloneable接口。4> 没有抽象方法的接口叫标识接口。5> 为什么我们在派...

LINUX进程组调度机制分析【转】

转自:https://oenhan.com/task-group-sched 又碰到一个神奇的进程调度问题,在系统重启过程中,发现系统挂住了,过了30s后才重新复位,真正系统复位的原因是硬件看门狗重启的系统,而非原来正常的reboot流程。硬件狗记录的复位时间,将不喂狗的时间向前推30s分析串口记录日志,当时的日志就打印了一句话:“sched: RT th...

二、实践与视频解决方案

一、视频解决方案 说明: 公司下户拍摄视频,上传存储一直用的优酷云(视频压缩、解码、播放)当然还支持水印。 现在场景,我们公司内部买服务器,下户拍摄视频上传到我们自己服务内,需要解决的问题,下户拍摄视频很大,需要解决的问题: 1、(下户视频过大)需要压缩处理、 2、(视频格式、播放帧处理)解码格式 3、(提供url)提供接口让内部人员可以播放  解决方案1...