java调用c/c++代码

article/2025/10/17 0:16:32

JNI是Java Native Interface的英文缩写, 中文翻译为本地调用, 自从Java 1.1开始就成为了Java标准的一部分。

C/C++是系统级的编程语言, 可以用来开发任何和系统相关的程序和类库, 但是Java本身编写底层的应用比较难实现, 使用JNI可以调用现有的本地库, 极大地灵活了Java的开发。

C/C++的效率是目前最好的语言, 可以使用C/C++来实现一些实时性非常高的部分. C/C++和Java本身都是非常流行的编程语言, 一些大型软件中经常使用语言之间的混合编程。

鉴于目前网络上JNI的文章不是特别多, 我将自己的一些总结写在这里. 如有错漏, 欢迎指正!

Java调用C/C++大概有这样几个步骤

  • 编写带有native方法的Java类, 使用javac工具编译Java类
  • 使用javah来生成与native方法对应的头文件
  • 实现相应的头文件, 并编译为动态链接库(windows下是.dll, linux下是.so)

下面就完整的介绍一个简单的Java调用C/C++的例子, 这个例子是来自http://www.ibm.com/developerworks/cn/education/java/j-jni/index.html, 不过其中有一些错误, 这个文章是非常不错的JNI学习资料, 但是非常古老.

编写Java类

我们来编写一个Sample1的java类

public class Sample1 {public native int intMethod(int n);public native boolean booleanMethod(boolean bool);public native String stringMethod(String text);public native int intArrayMethod(int[] intArray);public static void main(String[] args) {System.loadLibrary("Sample1");Sample1 sample = new Sample1();int square = sample.intMethod(5);boolean bool = sample.booleanMethod(true);String text = sample.stringMethod("Java");int sum = sample.intArrayMethod(new int[]{1,2,3,4,5,8,13});System.out.println("intMethod: " + square);System.out.println("booleanMethod: " + bool);System.out.println("stringMethod: " + text);System.out.println("intArrayMethod: " + sum);}
}


上面有4个native方法, 分别是4种类型的参数, int, boolean, String, int[].

其中有一句比较重要, 这句话加载了动态类库

 
  1. System.loadLibrary("Sample1");

在windows下加载的就是Sample1.dll, 在linux下加载的就是Sample1.so。

本文使用的windowws, 所以后面使用Sample1.dll来表示Sample1动态链接库。

注意:不可以在代码中写上后缀dll或so. 还要保证Sample1.dll在path路径中. 这个Sample1.dll是我们后面需要编译出来的东西。

4个native方法就是我们需要用C来实现的方法。

编译Sample1.java, 使用命令行(windows是cmd, linux下一般是bash)

>javac Sample1.java

可以看到Sample1.class文件

使用javah生成头文件

在命令行中运行

>javah Sample1

可以在目录下看到一个新文件Sample1.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Sample1 */#ifndef _Included_Sample1
#define _Included_Sample1
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     Sample1* Method:    intMethod* Signature: (I)I*/
JNIEXPORT jint JNICALL Java_Sample1_intMethod(JNIEnv *, jobject, jint);/** Class:     Sample1* Method:    booleanMethod* Signature: (Z)Z*/
JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod(JNIEnv *, jobject, jboolean);/** Class:     Sample1* Method:    stringMethod* Signature: (Ljava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *, jobject, jstring);/** Class:     Sample1* Method:    intArrayMethod* Signature: ([I)I*/
JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod(JNIEnv *, jobject, jintArray);#ifdef __cplusplus
}
#endif
#endif


我们可以看到其中有四个函数声明, Java_完整类名_方法名, 完整类名包括了包名, 例如demo.Sample1是完整类名, 对应的这里就是demo_Sample1.

在注释中我们可以看到这样一个东西 Signature, 这个是方法的签名. 关于Signature, 下面通过一个表格来说明。

java类型Signature备注
booleanZ 
byteB 
charC 
shortS 
intI 
longL 
floatF 
doubleD 
voidV 
objectL用/分割的完整类名例如: Ljava/lang/String表示String类型
Array[签名例如: [I表示int数组, [Ljava/lang/String表示String数组
Method(参数签名)返回类型签名例如: ([I)I表示参数类型为int数组, 返回int类型的方法

上面头文件的第一个函数声明

 
  1. JNIEXPORT jint JNICALL Java_Sample1_intMethod (JNIEnv *, jobject, jint);

注释中的签名是 Signature: (I)I

在每个函数的参数列表中都有JNIEnv *和 jobject两个参数, 这两个参数稍候说明。

实现头文件中的函数

可以使用C语言来实现, 也可以使用C++来实现, 下面先说说C语言的实现。

#include "Sample1.h"
#include <string.h>JNIEXPORT jint JNICALL Java_Sample1_intMethod(JNIEnv *env, jobject obj, jint num)
{return num * num;
}JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod(JNIEnv *env, jobject obj, jboolean boolean)
{return !boolean;
}JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring string)
{const char* str = (*env)->GetStringUTFChars(env, string, 0);char cap[128];strcpy(cap, str);(*env)->ReleaseStringUTFChars(env, string, 0);return (*env)->NewStringUTF(env, strupr(cap));
}JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod(JNIEnv *env, jobject obj, jintArray array)
{int i, sum = 0;jsize len = (*env)->GetArrayLength(env, array);jint *body = (*env)->GetIntArrayElements(env, array, 0);for (i = 0; i < len; ++i){sum += body[i];}(*env)->ReleaseIntArrayElements(env, array, body, 0);return sum;
}


(*env)->GetStringUTFChars()这个方法, 是用来在Java和C之间转换字符串的, 因为Java本身都使用了双字节的字符, 而C语言本身都是单字节的字符, 所以需要进行转换.

JNIEnv *是每个函数都有的参数, 它包含了很多有用的方法, 使用起来类似Java的反射, 也提供了这样一个编码转换的函数.

GetStringUTFChars()和NewStringUTF(), 第一个是从UTF8转换为C的编码格式, 第二个是根据C的字符串返回一个UTF8字符串.

ReleaseStringUTFChars()是用来释放对象的, 在Java中有虚拟机进行垃圾回收, 但是在C语言中, 这些对象必须手动回收. 否则可能造成内存泄漏.

函数的名字一眼看到就可以猜出功能, jni.h中的大部分函数名都是这样.

如果是C++的话, 这段代码该怎么写?

下面是C++的代码

#include "Sample1.h"
#include <string.h>JNIEXPORT jint JNICALL Java_Sample1_intMethod(JNIEnv *env, jobject obj, jint num)
{return num * num;
}JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod(JNIEnv *env, jobject obj, jboolean boolean)
{return !boolean;
}JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring string)
{const char* str = env->GetStringUTFChars(string, 0);char cap[128];strcpy(cap, str);env->ReleaseStringUTFChars(string, 0);return env->NewStringUTF(strupr(cap));
}JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod(JNIEnv *env, jobject obj, jintArray array)
{int i, sum = 0;jsize len = env->GetArrayLength(array);jint *body = env->GetIntArrayElements(array, 0);for (i = 0; i < len; ++i){sum += body[i];}env->ReleaseIntArrayElements(array, body, 0);return sum;
}


上述两端代码非常相似, 只有一个不同点

C代码: (*env)->GetStringUTFChars(env, string, 0);

C++代码: env->GetStringUTFChars(string, 0);

C语言中使用的是结构体的函数指针, 而在C++中使用的还是struct, 我们知道struct在C++中和class的功能是几乎一样的, struct也可以用来定义类, 所以env在C++中是个类对象的指针.

编译和运行


这里使用的是微软编译器, 编译C语言版的dll

>cl -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -LD Sample1.c -FeSample1.dll

编译C++版本的dll

>cl -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -LD Sample1.cpp -FeSample1.dll

运行

>java Sample1

注意: 64位版本的JDK可能会在运行时报错:

java.lang.UnsatisfiedLinkError: ...Sample1.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

如果您有这样的错误, 请使用32位的JDK来重新运行.

运行结果如下:

intMethod: 25 
booleanMethod: false 
stringMethod: JAVA 
intArrayMethod: 36

源代码下载: Sample1.zip

运行其中的build&run.bat文件即可, 如有错误请根据实际情况修改其中的一些参数.

DLL工程文件VC6.0和VS2010的: VC6.0&VS2010.zip

参考文献:

  1. Scott Stricker, 用 JNI 进行 Java 编程, http://www.ibm.com/developerworks/cn/education/java/j-jni/section2.html
  2. JDK 6u30 docs, Java Native Interface Specification, Chapter 3 JNI Types and Data Structures, Type Signatures.

原文链接:http://www.cnblogs.com/icejoywoo/archive/2012/02/22/2363709.html


http://chatgpt.dhexx.cn/article/H6WhpBZD.shtml

相关文章

java调用C++代码

首先我的参考博客如下&#xff1a; https://www.cnblogs.com/CLAYJJ/p/7725975.html https://www.cnblogs.com/xiaocainiao2hao/p/5619862.html https://www.cnblogs.com/langtianya/p/3470896.html 流程如下&#xff1a; 1.建立一个java文件&#xff0c;在这里我只写了一…

C语言调用Java JNI

最近项目中需要使用JNI&#xff0c;所以研究了一下&#xff0c;其中遇到过不少问题&#xff0c;总结一下&#xff0c;让遇到同样问题的人可以得到解决。 在C/C中调用Java的方法一般分为五个步骤&#xff1a;初始化虚拟机、获取类、获取类的方法、创建类对象、调用方法和退出虚…

java程序如何调用C++代码

看到java多线程中的Thread.isAlive()的类型为native&#xff0c;进一步去联想native方法什么时候用呢&#xff1f;自己能不能编写native方法&#xff1f; 经网上查资料&#xff1a; java中native修饰符的含义为“a native method is a java method whose implementation is p…

Java调用C++程序实现方法

Java调用C程序实现方法(1) 这篇博文是自己在学习过程中&#xff0c;踩了很多坑之后&#xff0c;为了避免广大热爱编程的盆友再像我这样浪费太多时间&#xff0c;索性将自己的实现方法总结出来&#xff0c;以供大家参考。程序最终实现的是Hello World效果&#xff0c;话不多说&…

从 C/C++ 程序调用 Java 代码

JNI允许您从本机代码内调用 Java 类方法。 要做到这一点&#xff0c;通常必须使用 Invocation API 在本机代码内创建和初始化一个 JVM。 下列是您可能决定从 C/C 代码调用Java 代码的典型情况&#xff1a; 1.希望实现的这部分代码是平台无关的&#xff0c;它将用于跨多种平台…

使用Java调用C/C++

文章目录 前言JNI概述例子编写Java代码编译生成的class文件:JNITest.class在命令行下使用javah生成C/C头文件。在工程的bin目录下输入以下命令&#xff1a;实现C代码。在VS2008中创建一个Win32 project&#xff0c;类型为DLL。构建C项目将dll文件复制到Java工程的bin目录下 前言…

java调用c/c++

最近项目想将比较重要的配置文件加密、综合考虑后决定用java jni实现&#xff0c;步骤如下 1.定义java本地接口 package com.msg.jni;public class JniMsg {static {try {String os System.getProperty("os.name").toLowerCase();String path "F:/opt/"…

C/C++如何调用Java

前言 简单介绍C/C如何调用Java&#xff0c;内容适合未接触过此类工程的朋友作为上手参考。 一、编译环境 1. 64位的win10系统 2. JDK&#xff1a;jdk-8u181-windows-x64.exe 3. IDE VS2017 二、调用步骤及Java虚拟机使用方法 一般步骤&#xff1a; 编写Java代码, 并编译…

java调用C

文章目录 idea创建一个java类通过命令生成.h文件vs2015创建dll项目修改dll项目的属性补充dll项目的头文件和源文件导入文件源文件的制作 生成dll文件idea导入dll文件idea使用函数 这个确实卡了我一段时间。 先说说必要性吧。 java无法处理的操作&#xff08;指向地址&#xff…

Java调用c/c++(JNI)最详细步骤

一、JNI(Java Native Interface)的作用就是Java通过JNI调用其他语言的函数(或方法)&#xff08;主要是C&C&#xff09;。 二、准备 1. java8系列jdk&#xff0c;有很多版本&#xff0c;任选一个即可&#xff0c;如jdk1.8.0.231。安装好&#xff0c;配置好环境。 2. vs20…

使用java调用C语言程序教程

1.idea创建一个java类 严格来说&#xff0c;核心步骤并不是创建一个java类&#xff0c;而是创建一个方法&#xff0c;那个方法要被native修饰&#xff0c;这才是关键。 接着在TestNativeCode类当中声明我们的本地方法&#xff1a; package com.wwj.nativecode; public class T…

linux中文语言包下载地址,centos中文语言包-官方版-centos中文语言包fonts-chinese-3.02-12.el5.noarch.rpm-独木成林...

centos中文语言包 fonts-chinese-3.02-12.el5.noarch.rpm&#xff0c;直接在目录下运行&#xff1a; rpm -ivh fonts-chinese-3.02-12.el5.noarch.rpm linux中文文件名乱码的解决办法(安装中文支持包) 由于安装英文版的系统不支持中文&#xff0c;出现中文文件名乱码。 下面操作…

Linux-centos安装MySQL8.0.22连接驱动文件mysql-connector-java-8.0.22-1.el7.noarch.rpm

目录 1、下载地址 2、选择版本 3、安装驱动 1、下载地址 https://downloads.mysql.com/archives/c-j/ 2、选择版本 选择对应的版本&#xff0c;这里系统选择Redhat系列Linux7&#xff0c;驱动版本选择8.0.22&#xff0c;点击download下载到本地再上传至服务器安装。 也可…

Mysql-MHA 安装过程中遇到的问题 :报错rpm -ivh mha4mysql- manager- 0.56-0.el6.noarch.rpm错误:依赖检测失败:

rpm -ivh mha4mysql- manager- 0.56-0.el6.noarch.rpm 错误&#xff1a;依赖检测失败&#xff1a; perl(Config::Tiny) 被 mha4mysql-manager-0.56-0.el6.noarch 需要 perl(Log::Dispatch) 被 mha4mysql-manager-0.56-0.el6.noarch 需要 perl(Log::Dispatch::File) 被 mha4mysq…

Linux下载并安装rabbitmq-server-3.6.5-1.noarch.rpm

目录 1.安装rabbitmq所需要的依赖包 2.下载安装包 3.安装服务命令 4.修改配置 5.启动rabbitmq 6.rabbitmq控制台安装 7.访问你的虚拟机 ip:15627 会出现下面的页面 用户名和密码都是 guest 8.常用命令 1.安装rabbitmq所需要的依赖包 yum install build-essential o…

centos rpm安装mysql时依赖检测失败:mysql57-community-release 与 mysql80-community-release-el8-3.noarch 冲突

1.出现以上报错&#xff0c;说明MySQL安装版本冲突 首先卸载原来的MySQL rpm -qa |grep mysql //搜索安装的MySQL包rpm -e --nodeps 搜索出来的包名 //卸载示例&#xff1a; [rootcentos8s ~]# rpm -qa |grep mysql mysql57-community-release-el7-11.noarch [rootcent…

yum 安装daemonize 错误:依赖检测失败: daemonize 被 jenkins-2.303.1-1.1.noarch 需要

错误&#xff1a;依赖检测失败&#xff1a; daemonize 被 jenkins-2.303.1-1.1.noarch 需要 安装 epel-release yum -y install epel-release安装 daemonize yum -y install daemonize结果&#xff1a;

php代码解决乱码问题

在用php的passthru函数的时候&#xff0c;然后出现了乱码的情况 代码&#xff1a; <?php echo passthru("ipconfig"); ?> 解决方法&#xff1a; 在原来的代码前面加 header("content-type:text/html;charsetgbk2312"); charset——后面是修改…

PHP-MySQL乱码[?]问题处理

PHP-MySQL乱码[?]问题处理 PHP-MySQL乱码[?]问题处理问题展示原因分析查看数据库编码格式WindowsLINUX 解决方案1、修改MySQL配置文件2、修改php连接数据库的编码格式。 修改后结果展示 PHP-MySQL乱码[?]问题处理 问题展示 php执行sql语句返回结果为’???’ 原因分析…

PHP文件乱码解决

1.查看项目的编码格式是不是UTF-8 2.在页面的开始处加入下面代码 <?php header("content-type:text/html;charsetutf-8"); //设置编码 ?>3.如果是html和PHP语言混合的PHP文件&#xff0c;还需要<head>标签下&#xff0c;加如下代码&#xff1a; <…