Java Native Interface 使用指南
我们知道Java本身的实现,很大一部分是用C++写的。实际上,Java也允许我们和原生平台的代码进行交互。
Java定义了一个接口规范,就叫做Java Native Interface,通过这个接口规范,我们就可以让Java代码运行原生平台的代码。
首先写一个Java的Class1:
public class HelloJNI {static {System.loadLibrary("hello"); // Load native library at runtime// hello.dll (Windows) or libhello.so (Unixes)}// Declare a native method sayHello() that receives nothing and returns voidprivate native void sayHello();// Test Driverpublic static void main(String[] args) {new HelloJNI().sayHello(); // invoke the native method}
}
从上面的代码,我们看到一些平常写Java代码的时候不常看见的东西,首先是这个:
System.loadLibrary("hello");
这个System.loadLibrary方法可以用来调用平台的原生库。然后是这个:
private native void sayHello();
这个native关键字意味着这个代码的实现是原生平台实现,而不是Java代码。因此我们要做一个hello库,提供这个sayHello方法。
接下来我们用javah命令生成.h文件:
$ ls HelloJNI.java
HelloJNI.java
$ javah HelloJNI
$ ls *.h
HelloJNI.h
我们得到了HelloJNI.h文件,它的内容是根据HelloJNI.java生成的,我们看看里面的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class: HelloJNI* Method: sayHello* Signature: ()V*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif
可以看到上面的文件里自动生成了JNI接口规范的一些约定代码。比如jni.h这个是由JDK提供的,我们稍后要引用。还有sayHello对应的C/C++的方法是Java_HelloJNI_sayHello,这个命名方式可以看出来是Java_ClassName_MethodName,这个也是JNI的约定。
接下来我们写一个HelloJNI.c来实现这个HelloJNI.h:
#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {printf("Hello World!\n");return;
}
这个代码就非常简单,就是实现了Java_HelloJNI_sayHello,功能就是printf("Hello World!\n");。我们编译这个代码:
$ c++ -c -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" HelloJNI.c
注意我是在MacOS上编译,所以引用的是MacOS的JDK的include目录,此外MacOS的内核名叫darwin,你如果用Linux系统,你的JDK的include目录里应该有一个linux目录,对应上面的darwin目录。
这两个-I主要是为了引用JNI相关的库文件:
$ ls $JAVA_HOME/include/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/jni.h
$ ls $JAVA_HOME/include/darwin/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/darwin/jni_md.h
这两个.h文件是必须的。编译完成后,我们就得到了object文件:
$ ls *.o
HelloJNI.o
用nm命令看一下这个object file里面的符号:
$ nm HelloJNI.o
0000000000000000 T _Java_HelloJNI_sayHelloU _printf
可以看到包含的的methods。我们要把这个object文件链接成library,在MacOS下命令如下:
$ c++ -dynamiclib -o libhello.jnilib HelloJNI.o
这样我们就得到了Java可以调用的libhello.jnilib:
$ ls *.jnilib
libhello.jnilib
我们在Java代码里写的是System.loadLibrary("hello"),但是这里的library名字叫做libhello,前面多了lib,这是一种命名约定。
如果你在Linux系统下,生成library的命令不太一样,需要用下面的命令生成.so文件,也就是shared library文件:
cc -shared -fpic -o libhello.so -I/usr/java/include -I/usr/java/include/linux HelloJNI.c
接下来就是编译Java代码:
$ javac HelloJNI.java
我们得到class文件:
$ ls *.class
HelloJNI.class
此时目录里应该有我们的library还有class文件:
$ ls *.class *.jnilib
HelloJNI.class libhello.jnilib
此时我们可以使用java命令运行HelloJNI.class:
$ java HelloJNI
Hello World!
可以看到我们这个Hello World!字符串是来自于native method的Java_HelloJNI_sayHello里面的printf。我们的Java代码与原生平台进行了交互。
参考资料:
-
https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.htm
相关文章:
Java Native Interface 使用指南
我们知道Java本身的实现,很大一部分是用C写的。实际上,Java也允许我们和原生平台的代码进行交互。 Java定义了一个接口规范,就叫做Java Native Interface,通过这个接口规范,我们就可以让Java代码运行原生平台的代码。…...
代码随想录算法训练营第三十九天 | 62.不同路径、63. 不同路径 II、343. 整数拆分、96.不同的二叉搜索树
62.不同路径 题目链接:https://leetcode.cn/problems/unique-paths/ 文档讲解:https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE… 视频讲解:https://www.bilibili.com/video/BV1ve4y1x7Eu/ 思路 确定dp数组以及下标的含…...
C/C++函数指针、C#委托是什么?
函数指针 #include<stdio.h>//声明函数指针 typedef int(*Calc)(int a, int b); int Add(int a, int b) {return a b; } int Sub(int a, int b) {return a - b; }int main() {Calc funcPoint1 &Add;Calc funcPoint2 ⋐int x 120;int y 140;int z 0;z …...
红队攻防渗透技术实战流程:组件安全:JacksonFastJsonXStream
红队攻防渗透实战 1. 组件安全1.1 J2EE-组件Jackson-本地demo&CVE1.1.1 代码执行 (CVE-2020-8840)1.1.2 代码执行(CVE-2020-35728)1.2 J2EE-组件FastJson-本地demo&CVE1.2.1 FastJson <= 1.2.241.2.2 FastJson <= 1.2.471.2.3 FastJson <= 1.2.801.3 J2EE-组…...
Perl 语言学习进阶
一、如何深入 要深入学习Perl语言的库和框架,可以按照以下步骤进行: 了解Perl的核心模块:Perl有许多核心模块,它们提供了许多常用的功能。了解这些模块的功能和用法是深入学习Perl的第一步。一些常用的核心模块包括:S…...
LangGraph实战:从零分阶打造人工智能航空客服助手
❝ 通过本指南,你将学习构建一个专为航空公司设计的客服助手,它将协助用户查询旅行信息并规划行程。在此过程中,你将掌握如何利用LangGraph的中断机制、检查点技术以及更为复杂的状态管理功能,来优化你的助手工具,同时…...
R可视化:R语言基础图形合集
R语言基础图形合集 欢迎大家关注全网生信学习者系列: WX公zhong号:生信学习者Xiao hong书:生信学习者知hu:生信学习者CDSN:生信学习者2 基础图形可视化 数据分析的图形可视化是了解数据分布、波动和相关性等属性必…...
mysql导入sql文件失败及解决措施
1.报错找不到表 1.1 原因 表格创建失败,编码问题mysql8相较于mysql5出现了新的编码集 1.2解决办法: 使用vscode打开sql文件ctrlh,批量替换,替换到你所安装mysql支持的编码集。 2.timestmp没有设置默认值 Error occured at:20…...
JS:获取鼠标点击位置
一、获取鼠标在目标元素中的点击位置 getClickPos.ts: export const getClickPos (e: MouseEvent) > {return {x: e.offsetX,y: e.offsetY,}; };二、获取鼠标在页面中的点击位置 getClickPos.ts: export const getPageClickPos (e: MouseEvent) > {return {x: e.pa…...
使用开源的zip.cpp和unzip.cpp实现压缩包的创建与解压(附源码)
目录 1、使用场景 2、压缩包的创建 3、压缩包的解压 4、CloseZipZ和CloseZipU两接口的区别...
npm 异常:peer eslint@“>=1.6.0 <7.0.0“ from eslint-loader@2.2.1
node 用16版本 npm install npm6.14.15 -g将版本降级到6...
Docker|了解容器镜像层(2)
引言 容器非常神奇。它们允许简单的进程表现得像虚拟机。在这种优雅的底层是一组模式和实践,最终使一切运作起来。在设计的根本是层。层是存储和分发容器化文件系统内容的基本方式。这种设计既出人意料地简单,同时又非常强大。在今天的帖子[1]中…...
使用Python爬取temu商品与评论信息
【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作! 【&…...
mybatis学习--自定义映射resultMap
1.1、resultMap处理字段和属性的映射关系 如果字段名和实体类中的属性名不一致的情况下,可以通过resultMap设置自定义映射。 常规写法 /***根据id查询员工信息* param empId* return*/ Emp getEmpByEmpId(Param("empId") Integer empId);<select id…...
Elasticsearch之写入原理以及调优
1、ES 的写入过程 1.1 ES支持四种对文档的数据写操作 create:如果在PUT数据的时候当前数据已经存在,则数据会被覆盖,如果在PUT的时候加上操作类型create,此时如果数据已存在则会返回失败,因为已经强制指定了操作类型…...
python中装饰器的用法
最近发现装饰器是一个非常有意思的东西,很高级! 允许你在不修改函数或类的源代码的情况下,为它们添加额外的功能或修改它们的行为。装饰器本质上是一个接受函数作为参数的可调用对象(通常是函数或类),并返…...
php实现一个简单的MySQL分页
一、案例演示: 二、php 代码 <?php $servername "localhost"; // MySQL服务器名称或IP地址 $username "root"; // MySQL用户名 $password "123456"; // MySQL密码 $dbname "test"; // 要连接…...
算法训练营day23补签
题目1:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode) class Solution { public:int reslut INT_MAX;TreeNode* pre NULL;void trackingback(TreeNode* node) {if(node NULL) return;trackingback(node->left);if(pre ! NULL) {reslut…...
国密SM2JS加密后端解密
1.前端加密 前端加密开源库 sm-crypto 1.1 传统web,下载 sm-crypto 进行打包为 dist/sm2.js 相关打包命令 npm install --save sm-crypto npm install npm run prepublish在web页面引用打包后的文件 <script type"text/javascript" src"<%path %>…...
Cheat Engine.exe修改植物大战僵尸阳光与冷却
Cheat Engine.exe修改植物大战僵尸阳光与冷却 打开Cheat Engine.exe和植物大战僵尸,点CE中文件下面红框位置,选择植物大战僵尸,点击打开 修改冷却: 等冷却完毕,首次扫描0安放植物,再次扫描变动值等冷却完…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
