JAVA 中使用 jni 调用 C++

前言

编程语言多种多样,在一个工程中有时会用到多种编程语言,这时就需要一个方法将两种语言联系起来,下文小编以 jni 为例,jni 用于在 JAVA 程序中引入 C 或 C++ 文件。

具体方法

  1. 首先在本地任意的一个目录下创建2各类 JNI.java 和 Test.java ,我在 D:\JNITest 目录下创建了这两个文件。
//JNI.java文件
public class JNI{
   //创建一个native接口方法,此方法在C++代码中实现
   public native int call();
   //静态代码块,加载由C++代码生成的.dll动态链接文件(.dll相当于Java中的jar包吧...)
   static{
       System.loadLibrary("JNIdll");
   }
}
//Test.java文件
public class Test{
    public static void main(String[] args){
        //创建JNI的对象call
        JNI call = new JNI();
        //调用call()方法;
        int i = call.call();
        //输出调用后的结果i
        System.out.println("调用Java Native Interface,返回:"+i);
    }
}

我的目录如下:
在这里插入图片描述

  1. 使用javac 编译JNI.java生成字节码文件JNI.class:
javac JNI.java

使用 javah 编译刚生成的字节码文件得到 JNI.h 文件,这里注意在使用 javah 时可能出现报错找不到类文件,试了网上的几种办法,以下方法亲测有效。
在想要存储生成的.h文件目录下 javah + -classpath + 项目包目录前 + -jni + 包名类名
比如:D:\Theta\Demo6\Test1\app\src> javah -classpath D:\Theta\Demo6\Test1\app\src\main\java -jni com.sikan.test1.JniUtils
在这里插入图片描述
打开 .h 文件,结构如下:
在这里插入图片描述

  1. 编写C++代码(JNIdll.cpp文件)来实现JNI.java中的call()方法(native修饰的)
//JNIdll.cpp文件

#include<stdio.h>
#include<jni.h>
#include "JNI.h"

JNIEXPORT jint JNICALL Java_JNI_call
  (JNIEnv *, jobject){
      //实现代码
      int i = 777;
      return i;
}
  1. 使用 vs 编译动态链接库
    新建动态链接库文件,
    在这里插入图片描述
    项目的命名即为最终生成的 dll 文件的名字,这里我取名 JNIdll ,在 JNIdll.cpp 文件中写入
//JNIdll.cpp文件

#include<stdio.h>
#include<jni.h>
#include "JNI.h"

JNIEXPORT jint JNICALL Java_JNI_call
  (JNIEnv *, jobject){
      //实现代码
      int i = 777;
      return i;
}

最后尤其注意一点,先确定运行 JDK 是32位还是64位,然后选择生成配置管理器,
在这里插入图片描述
生成的管理器界面如下:
在这里插入图片描述
根据 JDK 的位数选择32位和64位,另外这里要改的地方有两处,一处在平台,另一处在活动解决方案平台。 ,另外注意要把之前生成的头文件复制到和 JNIdll.cpp 相同的目录下,还有将java目录下的include目录下的两个文件jni.h和jni_md.h(jni_md.h在include目录下的win32目录中)拷贝到vc的include目录下。最后生成动态链接库,选择生成->重新生成解决方案。
在这里插入图片描述
之后在项目目录下生成 JNIdll.dll 文件。

  1. dll 文件复制到 java library path ,具体这个路径在哪,可以通过
System.out.println(System.getProperty("java.library.path"));

获取,将 JNIdll.dll 加入到 java.library.path 即可。最后运行 test.java 返回777。

  1. call 函数中加入自定义类
    我们想实现复杂一点的 call 函数,call 函数中有自定义类,我们首先需要定义自定义类,创建 person.h 文件,如下:
#pragma once
#ifndef PERSON_H_
#define PERSON_H_
#include <iostream>

using namespace std;
class person{//E,N,B,A,C
public:
	int a;
	person();
	~person();
};
#endif /* PERSON_H_ */

然后创建 person.cpp 文件,如下:

#include "person.h"
#include "stdafx.h"
#include <iostream>

using namespace std;

person::person() {
	a = 100000;
}
person::~person() {

}

这里注意一件事,就是所有的 cpp 文件中都要包含 stdafx.h 头文件,然后还要注意把 person.h 加入到stdafx.h 文件。如下:

// stdafx.h: 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 项目特定的包含文件
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>


#include "person.h"
// 在此处引用程序需要的其他标头
  1. call 函数中涉及文件读写
    我们现在想在 call 文件中添加读写操作,这里注意一定要写绝对路径,要不生成的 dll 执行的时候找不到路径。

结束语

本人大三学生一枚,学识尚浅,不喜勿喷,希望今日能抛砖引玉,请各位大佬一定不吝赐教!!!

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值