JNI_JAVA程序调用C/C++库_方法一

实际中,java语言有时还是会需要编写或使用其他语言的代码,这种代码通常成为本地代码

用java调用C/C++函数

JNI(Java Native Interface)

通过Java调用C++代码编写的 *.dll 类库中封装的方法,本 Demo 中包含两个方法,一个是输出文本信息,无返回值;一个计算并返回两个整数之和。

1. 编写Java接口
package package test.test_1;
public class test_1{    
    public native void sendMess(String mess);   
    public native int plusNum(int a,int b); 
}

编写完成后,生成 .class 文件。

2. 生成 *.h 头文件

进入 cmd 命令行,使用上一步生成的 .class 文件,利用 jdk 的 javah 命令生成 *.h 头文件

# 我的包名: package test.test_1
# javah
# -classpath :为.class 文件所在的根路径: E:\java\eclipse_wokespace\test_1\bin\ 
#   .class 文件的完整路径为E:\java\eclipse_wokespace\test_1\bin\test\test_1\test_1.class
# -d : 输出 *.h 头文件的路径: E:\java\eclipse_wokespace\
# -jni : 生成JNI样式的包头文件,可以理解成 *.class 文件的 包路径+类名
#  -jni 必须是*.class 文件的 包路径+类名,否则会报错。

进入文件夹:
E:\java\eclipse_wokespace\test_1\bin\test\test_1>
输入cmd命令:
javah -classpath E:\java\eclipse_wokespace\test_1\bin  -d E:\java\eclipse_wokespace\ -jni test.test_1.test_1

生成的test.test_1.test_1.h文件如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_test_1_test_1 */

#ifndef _Included_test_test_1_test_1
#define _Included_test_test_1_test_1
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_test_1_test_1
 * Method:    sendMess
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_test_11_test_11_sendMess
  (JNIEnv *, jobject, jstring);

/*
 * Class:     test_test_1_test_1
 * Method:    plusNum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_test_test_11_test_11_plusNum
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
3. 编写C++代码

1) 创建一个C++项目 ,名字:jni_1 ,设置应用类型为 dll
2) 将 jdk 安装目录下的 jni.h 、 jni_md.h 以及之前生成的 com_daniel_JNI_Test.h 放入项目根路径下的 include 文件夹 (需自己创建文件夹)
3) 添加项目VC++目录的包含目录,将上一步创建的 include 文件夹包含进项目。
4) 创建 test_jni.cpp 文件,并编写 c++ 代码实现,其中的方法头,可以从 生成的test.test_1.test_1.h文件中拷贝。 通过java来生成头文件从而获取描述符

# include<iostream>
# include<test_test_1_test_1.h>
using namespace std;

JNIEXPORT void JNICALL Java_test_test_11_test_11_sendMess
(JNIEnv *env, jobject obj, jstring str){
    char* t;
    t = (char*)env->GetStringUTFChars(str, 0);
    cout << t << endl;
}
JNIEXPORT jint JNICALL Java_test_test_11_test_11_plusNum
(JNIEnv *env, jobject obj, jint ia, jint ib){
    return ia + ib;
}

运行C++项目的生成按钮,并在生成路径下找到生成的 dll 文件(本文为 jni_1.dll)。生成的一定要是64位的dll。

4. Java调用C++ dll

将生成的 *.dll 添加到Java项目的 Native Library 中,修改最初的 JNI_Test.java 的代码,调用 dll 中的方法。

package test.test_1;

public class test_1{    
    public native void sendMess(String mess);   
    public native int plusNum(int a,int b);     
    static {
        System.loadLibrary("jni_1");
    }   
    public static void main(String[] args) {        
        test_1 tt= new test_1();
        tt.sendMess("Hi, FZX");
        System.out.println(tt.plusNum(5, 6));       
    }   
}
5. 添加知识点

jni中字段描述符:
jni中字段描述符
在C与java编程语言之间传递参数时,由于这两种语言对数字类型的实现不同,所以需要指定他们彼此之间的对应类型,数据类型之间的对应关系如下 :

int->jint,long->jlong,byte->jbyte,char->jchar,short->jshort,
float->jfloat,double->jdouble,boolean->jboolean

对于字符串参数,需要考虑编程语言之间的编码方式,java中的字符串是UTF-16编码点的序列,而C的字符串则是以null结尾的字节序列。java本地接口有两组操作字符串的函数,一组是把java字符串转换成改良的UTF-8字节序列,另一组将它们转换成UTF-16数值的数组,也就是转换成jchar数组。

jstring NewStringUTF(JNIEnv* env,const char bytes[])
    //根据改良的UTF-8字节序列,返回一个新的java字符串,当字符串无法构造时,返回null

    jsize getStringUTFLength(JNIEnv* env,jstring string)
    //返回进行UTF-8编码所需的字节数

    const ibyte* GetStringUTFChars(JNIEnv* env,jstring string,jboolean* isCopy)
    //返回改良UTF-8编码的字符串的指针,直到ReleaseStringUTFChars函数调用前该指针一直有效的。 

    void ReleaseStringUTFChars(JNIEnv* env,jstring string,const ibyte bytes[])
    //通知虚拟机本地代码不再需要通过bytes访问Java字符串

    void GetStringRegion(JNIEnv * env,jstring string,jsize start,jsize length,jchar *buffer)
    //将一个Unicode字符序列从字符串复制到用户提供的缓存中。

     void GetStringUTFREdion(JNIEnv * env,jstring string,jsize start,jsize length,jchar *buffer)
    //将一个改良的UTF-8字符序列从字符串复制到用户提供的缓存中。

参考博客:
https://blog.youkuaiyun.com/danielpei1222/article/details/62462497
https://blog.youkuaiyun.com/baidu_37464759/article/details/54915476

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值