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

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

    java与JNI数据类型对照表

    1、基本数据类型

     2、引用数据类型对照表

    二、Linux环境的准备(centos7)

     1、安装JDK(注意:不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件

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

      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"头文件


      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/ 

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

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

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

     8、jni方法签名规则
      

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

    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


     

     

  • 相关阅读:
    Prometheus服务发现
    持久化查询
    PromQL进阶
    PromQL基础
    Prometheus概述
    监控系统概念
    zabbix5x解决中文字体问题
    allure 插件新手 demo
    关于时间复杂度~
    IIS发布网站Microsoft JET Database Engine 错误 '80004005'的解决办法,基于Access数据库
  • 原文地址:https://www.cnblogs.com/ywbmaster/p/15293196.html
Copyright © 2011-2022 走看看