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 颜色模块中的其…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...
C# WPF 左右布局实现学习笔记(1)
开发流程视频: https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码: GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用(.NET Framework) 2.…...
安宝特案例丨寻医不再长途跋涉?Vuzix再次以AR技术智能驱动远程医疗
加拿大领先科技公司TeleVU基于Vuzix智能眼镜打造远程医疗生态系统,彻底革新患者护理模式。 安宝特合作伙伴TeleVU成立30余年,沉淀医疗技术、计算机科学与人工智能经验,聚焦医疗保健领域,提供AR、AI、IoT解决方案。 该方案使医疗…...
