C++调用Java接口
一、配置Java环境
安装jdk,我这里使用jdk1.8 32位版本,下载地址:https://www.oracle.com/java/technologies/downloads/#java8-windows

下载安装后,设置环境变量:

JAVA_HOME
C:\Program Files (x86)\Java\jdk-1.8

设置Path:


新增三个:
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin
%JAVA_HOME%\jre\bin\client

二、创建Java类
打开IDEA创建一个工程:例如JavaDemo

创建类:MyJavaClass

public class MyJavaClass {// 成员方法1,带参数,有返回值public String getSomething(String str){return str + " hello";}// 成员方法2,带参数,有返回值public int addNumber(int a1, int a2){return a1 + a2;}// 成员方法3,带参数,没有返回值public void printSomething(String str){System.console().printf(str);}// 静态方法,带参数,有返回值public static String staticMethodExample(String str){return str + " static method hello";}
}
在Main.java添加一些测试代码验证是否有问题:(为了避免MyJavaClass有问题,在这里调用一下MyJavaClass里的方法测试一下)

public class Main {public static void main(String[] args) {MyJavaClass myJavaClass = new MyJavaClass();String ret = myJavaClass.getSomething("Java");System.out.println("myJavaClass.getSomething return: " + ret);int num = myJavaClass.addNumber(1, 5);System.out.println("myJavaClass.addNumber return: " + num);myJavaClass.printSomething("Java");String ret2 = MyJavaClass.staticMethodExample("Java");System.out.println("MyJavaClass.staticMethodExample return: " + ret2);}
}
运行,得到结果:

三、生成jar
在项目中右键,选择Open Module Settings

选择Artifacts






最后,生成jar,在菜单栏选择 Build -> Build Artifacts

在菜单栏选择 Build -> Build Artifacts 后,在IDE的界面中随机在某个地方会出现下面的Build Artifact的弹窗,点击“Build”

Build完成后,就会在 out/artifacts 目录下生成jar文件

注意:如果JaveDemo引用了其他第三方库,也是会被一起打包到jar里面的
四、C++调Java接口示例
使用VS创建一个C++工程
属性设置:C/C++ -> General -> Additional Include Directories 添加:
$(JAVA_HOME)\include
$(JAVA_HOME)\include\win32

Linker -> General -> Additional Library Directories 添加:
$(JAVA_HOME)\lib

Linker -> General -> Additional Library Directories 添加: jvm.lib

创建一个main.cpp,添加代码:
#include <iostream>#include "jni.h"int main() {std::string jarFile = "../../JavaDemo/out/artifacts/JavaDemo_jar/JavaDemo.jar";std::string optionString = "-Djava.class.path=" + jarFile;JavaVMOption options[1];options[0].optionString = const_cast<char*>(optionString.c_str());JavaVMInitArgs vm_args;memset(&vm_args, 0, sizeof(vm_args));vm_args.version = JNI_VERSION_1_8;vm_args.nOptions = 1;vm_args.options = options;vm_args.ignoreUnrecognized = false;JavaVM* jvm = nullptr;JNIEnv* env = nullptr;// 启动虚拟机long status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if (status == JNI_ERR) {std::cout << "JNI_CreateJavaVM失败," << status << std::endl;return -1;}// 先获得class对象jclass cls = env->FindClass("MyJavaClass"); // 如果类带包名,这里需要加上包名,比如 com/example/MyJavaClass,把包名的.换成/if (cls == nullptr) {std::cout << "FindClass MyJavaClass 失败" << std::endl;return -1;}// 下面是调用成员方法和静态方法的示例,为了区分开来演示,用{}分开在两个作用域内。工作代码中不需要这样做。// 调用成员方法{// 查找构造函数并创建对象jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");if (constructor == nullptr) {std::cout << "查找构造函数失败" << std::endl;return -1;}jobject myJavaClassObj = env->NewObject(cls, constructor);if (myJavaClassObj == nullptr) {std::cout << "MyJavaClass类对象创建失败" << std::endl;jvm->DestroyJavaVM(); // 后面的代码只要退出应该都需要先释放VMreturn -1;}// 一、调用成员方法 getSomething 的示例{// 1. 获取成员方法getSomething的IDjmethodID getSomethingMethodid = env->GetMethodID(cls, "getSomething", "(Ljava/lang/String;)Ljava/lang/String;");if (getSomethingMethodid == nullptr) {std::cout << "getSomethingMethodid获取失败" << std::endl;return -1;}// 2. 调用成员方法getSomethingjstring inputString = env->NewStringUTF("Test"); // 这是成员方法getSomething的参数jstring ret = (jstring)env->CallObjectMethod(myJavaClassObj, getSomethingMethodid, inputString);const char* str = env->GetStringUTFChars(ret, 0);std::cout << "成员方法getSomething返回:" << str << std::endl;env->ReleaseStringUTFChars(ret, 0);}// 二、调用成员方法 addNumber 的示例{// 1. 获取成员方法getSomething的IDjmethodID addNumberMethodid = env->GetMethodID(cls, "addNumber", "(II)I");if (addNumberMethodid == nullptr) {std::cout << "addNumberMethodid获取失败" << std::endl;return -1;}// 2. 调用成员方法getSomethingjint param1 = 1;jint param2 = 5;jint ret = (jint)env->CallObjectMethod(myJavaClassObj, addNumberMethodid, param1, param2);std::cout << "成员方法getSomething返回:" << ret << std::endl;}}// 调用静态方法{jmethodID methodId = env->GetStaticMethodID(cls, "staticMethodExample", "(Ljava/lang/String;)Ljava/lang/String;");if (methodId == nullptr) {std::cout << "获取静态方法staticMethodExample的id失败" << std::endl;return -1;}jstring inputString = env->NewStringUTF("Test"); // 这是静态方法staticMethodExample的参数jstring ret = (jstring)env->CallStaticObjectMethod(cls, methodId, inputString);const char* str = env->GetStringUTFChars(ret, 0);std::cout << "静态方法staticMethodExample返回:" << str << std::endl;env->ReleaseStringUTFChars(ret, 0);}// 释放jvmif (jvm){jvm->DestroyJavaVM();}return 0;
}
代码运行结果:

其中:
- 调用Java的成员函数,需要
先创建对象,获取成员函数的MethodID,然后再调用成员函数; - 调用Java的静态函数,
不需要创建对象,直接获取静态方法的MethodID,再调用即可; - GetMethodID和GetStaticMethodID获取方法ID时,需要填入
方法名和方法签名,具体转换如下表:
(1)基础类型:
| Java Type | Native Type | Signature |
|---|---|---|
| byte | jbyte | B |
| char | jchar | C |
| double | jdouble | D |
| float | jfloat | F |
| int | jint | I |
| short | jshort | S |
| long | jlong | J |
| boolean | jboolean | Z |
| void | void | V |
(2)引用数据类型:
| Java Type | Native Type | Signature |
|---|---|---|
| 所有对象 | jobject | L+classname +; |
| Class | jclass | Ljava/lang/Class; |
| String | jstring | Ljava/lang/String; |
| Throwable | jthrowable | Ljava/lang/Throwable; |
| Object[] | jobjectArray | [L+classname +; |
| byte[] | jbyteArray | [B |
| char[] | jcharArray | [C |
| double[] | jdoubleArray | [D |
| float[] | jfloatArray | [F |
| int[] | jintArray | [I |
| short[] | jshortArray | [S |
| long[] | jlongArray | [J |
| boolean[] | jbooleanArray | [Z |
-
方法签名组装方式:
(参数类型1参数类型2…)返回值类型
例如,(II)I 表示接受两个整数参数,返回一个整数。下面是一些方法签名的具体示例:
int add(int a, int b) => (II)I
String concat(String str1, String str2) => (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
void printMessage(String message) => (Ljava/lang/String;)V
boolean isValid(int number) => (I)Z还可以通过
javap -s -p指令获取对应的签名信息,例如,我在MyJavaClass.class生成的目录,执行:javap -s -p MyJavaClass

-
更多参考:https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
五、问题
- 下图是环境变量的问题,按照第一部分设置环境变量后,重启VS再试

- 32位与64位jdk不匹配的问题,如果C++程序是32位,jdk也要是32位,如果C++程序是64位,则jdk也需要为64位

六、其他
注意:开发环境可以安装完整的jdk,但是打包在其他电脑上运行,运行环境就只需要安装jre就可以
运行环境设置:
jre下载地址:https://www.oracle.com/java/technologies/downloads/#jre8-windows

设置环境变量Path:
C:\Program Files (x86)\ava\latest\jre-1.8\bin
C:\Program Files (x86)\ava\latest\jre-1.8\bin\client
七、代码
https://gitee.com/jie-xio/cpp_samples/tree/master/CppCallJavaDemo
相关文章:
C++调用Java接口
一、配置Java环境 安装jdk,我这里使用jdk1.8 32位版本,下载地址:https://www.oracle.com/java/technologies/downloads/#java8-windows 下载安装后,设置环境变量: JAVA_HOME C:\Program Files (x86)\Java\jdk-1.…...
C# datetimePicker
1. 直接把控件拉到设计器中,此时不要调整控件的values属性,这样就可以 打开后每次默认显示当天日期。 2. 属性Format long长日期格式默认值short短日期格式Time时间格式custom自定义时间格式在customFormat这个属性设置,比如yyyy-MM-dd HH…...
AI有关的学习和python
一、基本概念 AIGC(AI Generated content AI 生成内容) AI生成的文本、代码、图片、音频、视频。都可以成为AIGC。 Generative AI(生成式AI)所生成的内容就是AIGC AI指代计算机人工智能,模仿人类的智能从而解决问题…...
前端node.js入门
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 Node.js 入门概览 什么是Node.js? 为什么选择Node.js? 基础安装与环境配置 安装…...
无需标注的数据集
0:人 1:自行车 2:汽车 3:摩托车 4:飞机 5:公交车 6:火车 7:卡车 8:船 9:交通信号灯 10:消火栓 11:停车标志 12:停车计时器…...
C# 抽象工厂模式
栏目总目录 概念 抽象工厂模式是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。在抽象工厂模式中,一个抽象的工厂类负责定义创建产品对象的接口,但是具体工厂类将负责创建具体的产…...
java中 两个不同类对象list,属性一样,如何copy
如果您有两个不同的类,但它们拥有相同的属性,并且您想要从一个类的列表复制到另一个类的列表,您可以使用以下方法: 使用循环: 您可以遍历原始列表,并为每个元素创建目标类的新实例。 使用 Stream API&…...
文件上传总结
一、原理 通过界面上的上传功能上传了一个可执行的脚本文件,而WEB端的系统并未对其进行检测或者检测的逻辑做的不够好,使得恶意用户可以通过文件中上传的一句话木马获得操控权 二、绕过方法 1>前端绕过 1.删除前端校验函数 checkFile() 2.禁用js…...
网页突然被恶意跳转或无法打开?DNS污染怎么解决?
前言 在网上冲浪时,我们时常会遭遇DNS污染这一区域性攻击,几乎无人能幸免。受影响时:尝试访问正规网站可能会被错误导向赌博、色情或其他恶意站点。 1.我们为什么需要DNS 当我们想要访问一个网站时,就像拨打朋友的电话号码一样…...
Matlab进阶绘图第65期—带分组折线段的柱状图
带分组折线段的柱状图是在原始柱状图的基础上,在每组柱状图位置处分别添加折线段,以进行对比或添加额外信息。 由于Matlab中未收录带分组折线段的柱状图的绘制函数,因此需要大家自行设法解决。 本文使用自制的BarwithGroupedLine小工具进行…...
EasyMedia转码rtsp视频流flv格式,hls格式,H5页面播放flv流视频
在本文中,我们将介绍如何使用 EasyMedia 将 RTSP 视频流转码为 FLV 和 HLS 格式,并在 H5 页面上播放 FLV 流视频。EasyMedia 是一个支持多种流媒体协议的开源项目,非常适合用于这种转码和流媒体传输的场景。 前提条件 已经安装并配置好 Eas…...
FPGA实验6: 有时钟使能两位十进制计数器的设计
一、实验目的与要求 1.. 熟练掌握使用原理图设计较复杂电路; 2. 学习原理图设计中总线的表示以及使用方法。 二、实验原理 运用Quartus II 集成环境下的图形设计方法设计有时钟使能的两位十进制计数器。进行波形仿真和分析、引脚分配并下载到实验设备上进行功能…...
C# 委托函数 delegate
在C#中,委托(Delegate)是一种特殊的类型,它可以持有对方法的引用。 委托是实现事件的基础。事件本质上是多播委托,允许多个方法被触发 委托允许你将方法作为参数传递给其他方法,或者将方法作为返回值从方法…...
Vue3响应式高阶用法之`shallowReadonly()`
Vue3响应式高阶用法之shallowReadonly() 在现代前端开发中,Vue3 提供了丰富的响应式 API 来帮助开发者更高效地管理状态和数据。其中,shallowReadonly() 是一个非常有用的工具,适用于需要部分只读状态的场景。本文将详细介绍 shallowReadonl…...
Windows系统安全加固方案:快速上手系统加固指南 (下)
这里写目录标题 一、概述二、IP协议安全配置启用SYN攻击保护 三、文件权限3.1 关闭默认共享3.2 查看共享文件夹权限3.3 删除默认共享 四、服务安全4.1禁用TCP/IP 上的NetBIOS4.2 ### 禁用不必要的服务 五、安全选项5.1启动安全选项5.2禁用未登录前关机 六、其他安全配置**6.1防…...
记一次因敏感信息泄露而导致的越权+存储型XSS
1、寻找测试目标 可能各位师傅会有苦于不知道如何寻找测试目标的烦恼,这里我惯用的就是寻找可进站的思路。这个思路分为两种,一是弱口令进站测试,二是可注册进站测试。依照这个思路,我依旧是用鹰图进行了一波资产的搜集ÿ…...
Java笔试面试题AI答之线程Thread(1)
答案来自 Kimi AI 目录 1. 进程和线程的区别?2. Java语言创建线程的方式有哪些?3. Java线程有哪几种可用状态?4. Java同步方法和同步代码块的区别?5. 在监视器(Monitor)内部,如何做线程同步的?6. 什么是死…...
2.5 C#视觉程序开发实例2----图片内存管理
2.5 C#视觉程序开发实例2----图片内存管理 1 目标效果视频 mat-buffer 2 Mat 数组的定义 3 图片内存使用场合说明 3.1 程序加载或者切换程序时 3.2 设定时,注册图片 例如注册一个线速的图片 注册流程说明 3.3 外部触发时采集最新图片或者按钮点击时触发拍照 …...
Java核心 - 深入理解 Java 枚举类
作者:逍遥Sean 简介:一个主修Java的Web网站\游戏服务器后端开发者 主页:https://blog.csdn.net/Ureliable 觉得博主文章不错的话,可以三连支持一下~ 如有疑问和建议,请私信或评论留言! 前言 在Java中&…...
HOW - CSS 定义颜色值
目录 1. 十六进制颜色 (Hexadecimal Color)2. RGB 颜色 (RGB Color)3. HSL 颜色 (HSL Color)HSL 颜色模式示例 4. 预定义颜色名 (Named Colors)5. LCH 颜色 (LCH Color)6. Lab 颜色 (Lab Color)7. HWB 颜色 (HWB Color)8. CSS 颜色函数 (Color Function)9. CSS4 颜色模块中的其…...
鸿蒙SpeechKit离线语音识别避坑指南:从PCM格式到权限配置,一次搞定
鸿蒙SpeechKit离线语音识别实战避坑指南 1. 音频格式的致命陷阱 PCM格式是鸿蒙SpeechKit离线语音识别的唯一选择,但开发者常犯的错误远不止文件类型这么简单。我曾见过一个团队花费三天时间排查识别率低的问题,最终发现是采样深度设置错误——这个细节在…...
手把手教你用LVGL特殊符号打造炫酷UI界面
手把手教你用LVGL特殊符号打造炫酷UI界面 在嵌入式设备开发中,UI设计往往面临资源受限的挑战。LVGL(Light and Versatile Graphics Library)作为一款轻量级开源图形库,通过其丰富的特殊符号系统,让开发者能够在有限资…...
XML Notepad:免费高效的XML编辑器终极指南
XML Notepad:免费高效的XML编辑器终极指南 【免费下载链接】XmlNotepad XML Notepad provides a simple intuitive User Interface for browsing and editing XML documents. 项目地址: https://gitcode.com/gh_mirrors/xm/XmlNotepad XML Notepad是一款由微…...
EtherCAT模块化实战:如何为你的设备设计可热插拔的IO模块(基于SSC与0x4711示例)
EtherCAT模块化实战:如何为你的设备设计可热插拔的IO模块 在工业自动化领域,设备的灵活性和可扩展性正变得越来越重要。想象一下,当你的客户需要在生产线上快速更换不同类型的传感器或执行器时,如果每次硬件变更都需要重新配置整个…...
AIGC时代,程序员会被取代吗?我的看法与行动建议
AIGC时代,程序员会被取代吗?我的看法与行动建议 随着AI生成内容(AIGC)技术的迅猛发展,许多人开始担忧:程序员这一职业是否会被AI取代?从代码生成工具GitHub Copilot到对话式编程助手ChatGPT&am…...
自动化立体仓库堆垛机设计(设计说明书+17张CAD图纸+开题报告+任务书+实习报告+中期检查报告+外文翻译)
自动化立体仓库堆垛机作为现代物流系统的核心设备,其设计需兼顾机械结构强度、运动控制精度与系统稳定性。该设计通过三维建模与力学仿真验证,确保堆垛机在高速运行时的结构可靠性,同时优化货叉伸缩机构与载货台升降导轨的配合间隙࿰…...
Undecimus革新性全流程越狱技术指南:从核心价值到实用工具
Undecimus革新性全流程越狱技术指南:从核心价值到实用工具 【免费下载链接】Undecimus unc0ver jailbreak for iOS 11.0 - 12.4 项目地址: https://gitcode.com/gh_mirrors/un/Undecimus 一、核心价值:破解iOS生态三大痛点 Undecimus作为针对iOS…...
别再死记硬背公式了!Cesium中Entity姿态(HPR)的获取与设置,一个例子讲透
Cesium中Entity姿态控制的本质:从HPR到四元数的思维跃迁 当你第一次在Cesium中加载一个3D模型,却发现它头朝下或者背对镜头时,那种挫败感我深有体会。传统教程往往直接扔给你一堆转换公式,却很少解释为什么需要这些看似复杂的数学…...
别再死记硬背PCA公式了!用Python+Open3D实战点云法向量估计(附代码)
用Python实战点云法向量估计:从数学原理到Open3D实现 点云处理是计算机视觉和三维重建中的基础任务,而法向量估计则是理解点云局部几何特征的关键步骤。传统教学中,PCA(主成分分析)往往被简化为一堆数学公式ÿ…...
YOLOv11目标检测与伏羲气象模型的融合应用:灾害天气图像识别预警
YOLOv11目标检测与伏羲气象模型的融合应用:灾害天气图像识别预警 最近几年,极端天气好像越来越频繁了。有时候,一场突如其来的暴雨或浓雾,就能让整个城市的交通陷入瘫痪,甚至带来不小的经济损失。传统的天气预报&…...
