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 颜色模块中的其…...
UniAppX项目数据可视化升级:用lime-echart + ECharts打造高性能图表(从Vue2/Vue3到uni-app-x全流程)
UniAppX高性能数据可视化实战:lime-echart与ECharts的深度整合指南 当移动端数据可视化需求遭遇性能瓶颈时,UniAppX框架与lime-echart的组合正在成为技术决策者的新选择。本文将揭示如何在不同技术栈中实现图表渲染性能的突破性提升,从原理剖…...
效率提升秘籍:用快马AI自动生成六花直装更新页面,节省开发时间
作为一名经常需要维护应用更新页面的开发者,我深刻体会到手动编写更新日志的繁琐。每次版本迭代,从整理更新内容到排版发布,往往要耗费大量时间。最近尝试用InsCode(快马)平台的AI功能自动生成更新页面,效率提升非常明显。 传统更…...
Qt串口通信实战:用QSerialPort从零搭建一个串口调试助手(附完整源码)
Qt串口通信实战:从零构建工业级调试助手 在嵌入式开发和工业控制领域,串口通信作为最基础也最可靠的通信方式之一,至今仍发挥着不可替代的作用。无论是单片机与上位机的数据交换,还是工业设备的参数配置,一个稳定高效的…...
Word自动编号的隐藏玩法:用题注和交叉引用,打造能“自我修复”的智能文档
Word文档工程化:构建自动编号与交叉引用的智能系统 在技术文档撰写过程中,最令人头疼的莫过于图表编号的维护。当你在200页的文档中插入新图表时,手动编号意味着要逐个修改后续所有编号和引用——这种痛苦只有经历过的人才懂。但很少有人意识…...
Windows下RedisInsight保姆级安装教程:从下载到连接Redis全流程详解
Windows平台RedisInsight全流程实战指南:从零搭建高效Redis可视化环境 Redis作为当下最流行的内存数据库之一,其强大的性能与丰富的数据结构深受开发者青睐。但在日常开发中,仅通过命令行操作Redis难免效率低下——这正是RedisInsight的价值所…...
Nemo文件管理器终极指南:Cinnamon桌面环境下的高效文件管理神器
Nemo文件管理器终极指南:Cinnamon桌面环境下的高效文件管理神器 【免费下载链接】nemo File browser for Cinnamon 项目地址: https://gitcode.com/gh_mirrors/ne/nemo Nemo是Cinnamon桌面环境的官方文件管理器,作为一个免费开源的软件项目&#…...
如何快速上手MoMask:面向初学者的3D人体运动生成完整指南
如何快速上手MoMask:面向初学者的3D人体运动生成完整指南 【免费下载链接】momask-codes Official implementation of "MoMask: Generative Masked Modeling of 3D Human Motions (CVPR2024)" 项目地址: https://gitcode.com/gh_mirrors/mo/momask-code…...
一条命令搞定STM32程序下载:OpenOCD program命令的隐藏用法与避坑指南
STM32极速烧录秘籍:OpenOCD program命令高阶玩法全解析 每次调试STM32都要重复点击IDE的下载按钮?CI/CD流水线卡在烧录环节?是时候解锁OpenOCD的program命令了——这个被低估的"瑞士军刀"能让你用一行命令完成擦除、烧录、校验、复…...
4步构建高效视频处理流水线:VideoFusion全功能指南
4步构建高效视频处理流水线:VideoFusion全功能指南 【免费下载链接】VideoFusion 一站式短视频拼接软件 无依赖,点击即用,自动去黑边,自动帧同步,自动调整分辨率,批量变更视频为横屏/竖屏 项目地址: https://gitcode.com/gh_mirrors/vi/VideoFusion 功能特性…...
OliveTin高级功能指南:定时任务、文件监控和实体动态更新
OliveTin高级功能指南:定时任务、文件监控和实体动态更新 【免费下载链接】OliveTin OliveTin gives safe and simple access to predefined shell commands from a web interface. 项目地址: https://gitcode.com/gh_mirrors/ol/OliveTin OliveTin是一个强…...
