重新认识一下JNIEnv

server/2024/9/20 7:28:10/ 标签: c#, java-ee, java

JNIEnv

1.JNIEnv是什么?


JNIEnv 是 Java Native Interface (JNI) 中的一个重要结构,代表 JNI 环境的指针。它提供了一组函数,用于在本地代码(C/C++)中与 Java 虚拟机(JVM)进行交互。以下是对 JNIEnv 的详细介绍:

1. 定义

  • JNIEnv 是一个指向结构体的指针,包含了 JNI 函数的指针表。通过这个指针,开发者可以调用 JNI 提供的各种功能,如创建对象、调用方法、访问字段等。

2. 作用

  • 访问 Java 对象: JNIEnv 允许本地代码访问 Java 对象的属性和方法。
  • 调用 Java 方法: 可以通过 JNIEnv 调用 Java 方法,包括静态方法和实例方法。
  • 处理异常: JNIEnv 提供了处理 Java 异常的功能,可以检查和抛出异常。

3. 使用示例

以下是一个简单的示例,展示如何使用 JNIEnv 来调用 Java 方法:

3.1 Java 代码

java">// Example.java
public class Example {public void greet() {System.out.println("Hello from Java!");}
}

3.2 C/C++ 代码

#include <jni.h>
#include <stdio.h>int main() {JavaVM *jvm;             // Java 虚拟机JNIEnv *env;            // JNI 环境JavaVMInitArgs vm_args; // JVM 启动参数JavaVMOption options[1]; // JVM 选项// 设置 JVM 选项,指定类路径options[0].optionString = "-Djava.class.path=."; // 当前目录vm_args.version = JNI_VERSION_1_6; // JNI 版本vm_args.nOptions = 1; // 选项数量vm_args.options = options; // 选项数组vm_args.ignoreUnrecognized = 0; // 忽略未识别的选项// 创建 Java 虚拟机jint ret = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);if (ret != JNI_OK) {fprintf(stderr, "Failed to create JVM\\n");return 1;}// 查找 Example 类jclass cls = (*env)->FindClass(env, "Example");if (cls == NULL) {fprintf(stderr, "Failed to find Example class\\n");(*jvm)->DestroyJavaVM(jvm);return 1;}// 创建 Example 类的实例jobject obj = (*env)->AllocObject(env, cls);if (obj == NULL) {fprintf(stderr, "Failed to create Example object\\n");(*jvm)->DestroyJavaVM(jvm);return 1;}// 查找 greet 方法jmethodID mid = (*env)->GetMethodID(env, cls, "greet", "()V");if (mid == NULL) {fprintf(stderr, "Failed to find greet method\\n");(*jvm)->DestroyJavaVM(jvm);return 1;}// 调用 greet 方法(*env)->CallVoidMethod(env, obj, mid);// 销毁 Java 虚拟机(*jvm)->DestroyJavaVM(jvm);return 0;
}

4. 代码解析

  • 创建 JVM: 使用 JNI_CreateJavaVM 创建 Java 虚拟机,并获取 JNIEnv 指针。
  • 查找类和方法: 使用 FindClassGetMethodID 查找 Java 类和方法。
  • 调用方法: 使用 CallVoidMethod 调用 Java 方法。

5. 总结

JNIEnv 是 JNI 中与 Java 交互的关键结构,提供了丰富的 API 来操作 Java 对象和调用 Java 方法。通过 JNIEnv,本地代码可以方便地与 Java 进行交互,实现更复杂的功能。

(1)JNIEnv结构体介绍


JNIEnv 是 Java Native Interface (JNI) 中的一个重要结构体,它提供了本地代码与 Java 虚拟机 (JVM) 之间的接口。通过 JNIEnv,本地代码可以调用 Java 方法、访问 Java 对象的字段以及处理 Java 异常等。

1. JNIEnv 的定义

JNIEnv 是一个指向 JNI 环境的指针,通常在 JNI 函数中作为参数传递。每个线程都有自己的 JNIEnv 指针,允许线程安全地访问 JNI 函数。

2. JNIEnv 的结构

虽然 JNIEnv 的具体实现依赖于 JVM 的实现,但它通常包含一组函数指针,这些指针指向 JNI 提供的各种功能。以下是一些常用的 JNI 函数,通常在 JNIEnv 中定义:

  • 对象操作:
    • FindClass: 查找 Java 类。
    • AllocObject: 创建 Java 对象。
    • GetObjectField: 获取对象的字段值。
    • SetObjectField: 设置对象的字段值。
  • 方法调用:
    • GetMethodID: 获取方法 ID。
    • CallVoidMethod: 调用无返回值的方法。
    • CallObjectMethod: 调用返回对象的方法。
  • 异常处理:
    • ExceptionCheck: 检查是否发生异常。
    • ExceptionDescribe: 打印异常信息。
    • Throw: 抛出异常。
  • 数组操作:
    • GetIntArrayElements: 获取整型数组的元素。
    • ReleaseIntArrayElements: 释放整型数组的元素。

3. JNIEnv 的使用示例

以下是一个简单的示例,展示如何使用 JNIEnv 来调用 Java 方法:

#include <jni.h>
#include <stdio.h>void callJavaMethod(JNIEnv *env) {// 查找 Java 类jclass cls = (*env)->FindClass(env, "HelloWorld");if (cls == NULL) {printf("Failed to find HelloWorld class\\n");return;}// 获取方法 IDjmethodID mid = (*env)->GetMethodID(env, cls, "sayHello", "()V");if (mid == NULL) {printf("Failed to find sayHello method\\n");return;}// 创建对象并调用方法jobject obj = (*env)->AllocObject(env, cls);(*env)->CallVoidMethod(env, obj, mid);
}

4. 重要性

JNIEnv 是 JNI 编程的核心,提供了与 Java 交互的所有必要功能。通过 JNIEnv,本地代码可以灵活地操作 Java 对象和调用 Java 方法,从而实现 C/C++ 和 Java 之间的无缝集成。

5. 总结

JNIEnv 是一个指向 JNI 环境的指针,包含了与 Java 交互的所有函数。它在 JNI 编程中至关重要,允许本地代码访问 Java 的功能。理解 JNIEnv 的使用是成功进行 JNI 开发的关键。

(2)JNIEnv在c和c++中的区别


JNIEnv 是 Java Native Interface (JNI) 中的一个重要结构体,它提供了访问 Java 虚拟机的接口。虽然 JNIEnv 在 C 和 C++ 中的基本概念是相同的,但在使用上有一些细微的区别(重点在于参数)。以下是 JNIEnv 在 C 和 C++ 中的比较:

1. JNIEnv 的定义

  • C 语言: JNIEnv 是一个指向结构体的指针,通常在 C 代码中直接使用。
  • C++ 语言: JNIEnv 仍然是一个指向结构体的指针,但可以利用 C++ 的类和对象特性来封装 JNI 调用。

2. 使用方式

C 语言示例

在 C 语言中,使用 JNIEnv 进行 JNI 调用的方式如下:

#include <jni.h>void exampleFunction(JNIEnv *env) {jclass cls = (*env)->FindClass(env, "HelloWorld");// 其他 JNI 调用...
}

C++ 语言示例

在 C++ 中,使用 JNIEnv 的方式可以更灵活,通常会使用 C++ 的类和对象特性:

#include <jni.h>class Example {
public:void exampleFunction(JNIEnv *env) {jclass cls = env->FindClass("HelloWorld"); // 使用成员函数调用// 其他 JNI 调用...}
};

3. 方法调用

  • C 语言: 在 C 中,调用 JNI 方法时需要使用指针解引用的方式,例如 (*env)->FindClass(env, "HelloWorld")
  • C++ 语言: 在 C++ 中,可以直接使用 env->FindClass("HelloWorld"),这使得代码更简洁和易读。

4. 错误处理

在 C 语言中,错误处理通常通过返回值来实现,而在 C++ 中,可以使用异常处理机制(如果需要的话),这使得 C++ 的错误处理更加灵活。

5. 代码风格

  • C 语言: 更加注重过程式编程,代码结构相对简单。
  • C++ 语言: 支持面向对象编程,可以使用类、继承和多态等特性,使得代码更具可重用性和可维护性。

6. 总结

虽然 JNIEnv 在 C 和 C++ 中的基本功能是相同的,但在使用方式、代码风格和错误处理等方面存在一些区别。C++ 提供了更强大的语言特性,使得 JNI 的使用更加灵活和简洁。

2.JNIEnv的获取方式


JNIEnv 是 Java Native Interface (JNI) 中的一个重要结构体,它提供了访问 Java 虚拟机的接口。JNIEnv 结构体的具体实现可能会因平台和 JVM 的不同而有所不同,但它的主要作用是为本地代码提供与 Java 代码交互的功能。

1. JNIEnv 的定义

JNIEnv 是一个指向结构体的指针,包含了一系列函数指针,这些函数指针用于调用 JNI 提供的各种功能,如创建对象、调用方法、访问字段等。

2. JNIEnv 的获取方式

在 JNI 中,获取 JNIEnv 的方式主要有以下几种:

2.1 在 JNI 方法中

当你在 Java 中调用本地方法时,JVM 会自动将 JNIEnv 作为参数传递给该方法(函数静态或者动态注册,传的第一个参数)。示例:

JNIEXPORT void JNICALL Java_HelloWorld_nativeMethod(JNIEnv *env, jobject obj) {// 这里可以使用 env 进行 JNI 调用
}

2.2 在 JavaVM 中获取

如果你在非 JNI 方法(如线程创建函数)中需要获取 JNIEnv,可以通过 JavaVMGetEnv 方法获取:

JavaVM *jvm; // 假设已经创建了 JavaVM
JNIEnv *env;
jint ret = (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6);
if (ret != JNI_OK) {// 处理错误
}

2.3 在附加线程中

如果你在一个新线程中,需要将该线程附加到 JVM,并获取 JNIEnv

JavaVM *jvm; // 假设已经创建了 JavaVM
JNIEnv *env;
jint ret = (*jvm)->AttachCurrentThread(jvm, (void**)&env, NULL);
if (ret != JNI_OK) {// 处理错误
}

3. JNIEnv 的结构体

JNIEnv 的具体实现是 JVM 相关的,通常包含以下类型的函数指针(具体实现可能会有所不同):

  • 对象创建和管理: NewObject, NewGlobalRef, DeleteGlobalRef 等。
  • 方法调用: CallVoidMethod, CallObjectMethod, CallIntMethod 等。
  • 字段访问: GetFieldID, GetObjectField, SetObjectField 等。
  • 异常处理: ExceptionCheck, ExceptionDescribe, Throw 等。

4. C 和 C++ 中的 JNIEnv 使用区别

在 C 和 C++ 中,使用 JNIEnv 的方式略有不同,主要体现在以下几个方面:

4.1 C 代码示例

JNIEXPORT void JNICALL Java_HelloWorld_nativeMethod(JNIEnv *env, jobject obj) {jclass cls = (*env)->FindClass(env, "java/lang/String");// 其他 JNI 调用
}

4.2 C++ 代码示例

在 C++ 中,通常会使用 JNIEnv 的成员函数来调用 JNI 方法,使用 -> 操作符:

JNIEXPORT void JNICALL Java_HelloWorld_nativeMethod(JNIEnv *env, jobject obj) {jclass cls = env->FindClass("java/lang/String");// 其他 JNI 调用
}

5. 总结

JNIEnv 是 JNI 中与 Java 交互的关键结构体,获取方式主要通过 JNI 方法参数、JavaVMGetEnvAttachCurrentThread 方法。在 C 和 C++ 中,使用 JNIEnv 的方式略有不同,C++ 更加面向对象,通常使用 -> 操作符来调用方法。


http://www.ppmy.cn/server/117297.html

相关文章

CCS6 软件及仿真器驱动安装

1 CCS6 软件获取 TI 的官网上下载: http://www.ti.com/tools-software/ccs.html 注意 首先 win32 是 CCS 安装包支持 64 位系统,我们电脑也是 64 位系统也是安装的 win32 的安装包,另外 TI 只提供 win32 的安装包,无 win64 的安装包。 2 CCS6 软件安装 CCS如果获取提供的…

逆向学习系列(三)adb的使用

由于是记录学习&#xff0c;我就用结合自己的理解&#xff0c;用最通俗的语言进行讲解。 adb是android debug bridge的简写&#xff0c;其作用就是将电脑和手机相连接&#xff0c;用电脑控制手机。 一、adb哪里来 我使用的adb一般都是安装模拟器的时候&#xff0c;模拟器自带…

【物联网技术大作业】设计一个智能家居的应用场景

前言&#xff1a; 本人的物联网技术的期末大作业&#xff0c;希望对你有帮助。 目录 大作业设计题 &#xff08;1&#xff09;智能家居的概述。 &#xff08;2&#xff09;介绍智能家居应用。要求至少5个方面的应用&#xff0c;包括每个应用所采用的设备&#xff0c;性能&am…

PHP即刻送达同城派送小程序系统

即刻送达&#xff0c;同城派送小程序系统让生活更便捷 &#x1f680; 瞬间连接&#xff0c;即刻送达的奇迹 你是否曾经因为等待快递而焦急万分&#xff1f;是否渴望有一种方式能让物品像魔法一样瞬间出现在你面前&#xff1f;现在&#xff0c;有了“即刻送达同城派送小程序系…

vite+vue3快速构建项目+router、vuex、scss安装

安装 Vite npm install -g create-vite-app创建vue3项目 npm init vitelatestnpm i安装依赖 安装veux、router npm install vue-router vuex新建router/index.js&#xff08;自己创建home、login对应页面文件&#xff09; import { createRouter, createWebHistory } from…

python解析ip范围,拆分为所有ip数组

代码如下&#xff0c;还需结合一篇文章来看&#xff1a;ip范围格式转换 #! -*- coding:utf-8 -* """ desc: 解析ip范围为单ip列表 """import ipaddressdef ip_range_to_list(start_ip, end_ip):"""处理有明确起始ip的数据&#…

【PCB工艺】如何实现PCB板层间的互连

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言①、什么是通孔②、通孔是怎样产生的③、通孔种类④、盘中孔⑤、设计建议 前言 送给大学毕业后找不到奋斗方向的你…

LEAN 类型系统属性 之 算法式相等的非传递性(Algorithm equality is not transitive)注解

由于 subsingleton 使用函数&#xff08;eliminator&#xff09; 的存在&#xff0c;导致算法式相等&#xff08;Algorithm defintional equality&#xff09;的非传递性。 在《定义上相等的非确定性&#xff08;Undecidability of Definitional Equality&#xff09;》 中有&…

SpringBoot 处理 @KafkaListener 消息

消息监听容器 1、KafkaMessageListenerContainer 由spring提供用于监听以及拉取消息&#xff0c;并将这些消息按指定格式转换后交给由KafkaListener注解的方法处理&#xff0c;相当于一个消费者&#xff1b; 看看其整体代码结构&#xff1a; 可以发现其入口方法为doStart(),…

C# List定义和常用方法

栏目总目录 List的定义 列表&#xff08;List&#xff09;是一种常用的集合类型&#xff0c;它属于System.Collections.Generic命名空间。列表是一个有序集合&#xff0c;可以包含重复的元素&#xff0c;并且可以根据索引访问元素。 List< T > List<T> 是一个泛…

如何从github上clone项目

从GitHub上克隆项目是一个常见的操作&#xff0c;主要用于将GitHub仓库中的代码下载到本地计算机。以下是详细的步骤&#xff1a; 登录GitHub&#xff1a;首先&#xff0c;确保你已经在GitHub上注册了账号并登录。 找到项目仓库&#xff1a;在GitHub上找到你想要克隆的项目仓库…

linux 定时将固态硬盘数据备份至机械硬盘

需求背景 为了加强公司数据的安全性和可靠性&#xff0c;我们将实施一项数据备份策略。该策略涉及将服务器上的固态硬盘&#xff08;SSD&#xff09;中的关键数据定期备份到机械硬盘&#xff08;HDD&#xff09;上。这一过程旨在保护数据免受意外删除、硬件故障或其他潜在风险…

HOT 100(七)栈、堆、贪心算法

一、栈 1、每日温度 使用单调递减栈来解决。主要思路是遍历temperatures数组&#xff0c;利用栈来存储还没有找到比当前温度高的天数的索引。当遇到比栈顶索引所对应温度更高的温度时&#xff0c;就可以确定当前这一天的温度比之前那一天高。索引的差值就是等待的天数。 求一…

更换cuda版本

要更改链接&#xff0c;使其指向新的目标路径&#xff0c;可以按照以下步骤操作&#xff1a; 删除现有的软链接&#xff1a; 首先&#xff0c;删除现有的链接 /usr/local/cuda&#xff0c;可以使用 rm 命令来删除&#xff1a; sudo rm -rf /usr/local/cuda注意&#xff1a;使用…

Docker绑定端口后仍无法远程直接访问

在docker中拉取镜像后启动&#xff0c;启动脚本如下 启动docker docker run --name nacos-server \ -p 8848:8848 \ -p 7848:7848 \ -p 9848:9848 \ -p 9849:9849 \ --privilegedtrue \ --restartalways \ -e JVM_XMS256m \ -e JVM_XMX256m \ -e MODEstandalone \ -e PREFER_…

✨机器学习笔记(四)—— 逻辑回归、决策边界、过拟合、正则化

Course1-Week3: https://github.com/kaieye/2022-Machine-Learning-Specialization/tree/main/Supervised%20Machine%20Learning%20Regression%20and%20Classification/week3机器学习笔记&#xff08;四&#xff09; 1️⃣逻辑回归&#xff08;logistic regression&#xff09;…

【F的领地】项目拆解:科普类账号基础运营教程 | 学会使用工具 “偷懒” | 文字成片功能

初中同学&#xff0c;做了个科普类账号&#xff0c;半年转化了十几个&#xff0c;引发了我的兴趣。 账号也不做私域转化&#xff0c;而且就靠抖音橱窗…… 我这种天天和平台机制斗智斗勇的&#xff0c;看到能和平台同频的&#xff0c;不自然地感兴趣。 于是我就去问了一下细…

kafka 之 本地部署单机版

安装JDK 查看你选择的版本需要安装哪一个版本的jdk 网址 下载 JDK下载 注&#xff1a;如果网页不允许下载&#xff0c;使用wget命令下载即可&#xff0c;下载之后安装。 建议使用rpm安装&#xff0c;之后使用 update-alternatives --config java 控制当前环境使用Java的版…

Kafka+PostgreSql,构建一个总线服务

之前开发的系统&#xff0c;用到了RabbitMQ和SQL Server作为总线服务的传输层和存储层&#xff0c;最近一直在看Kafka和PostgreSql相关的知识&#xff0c;想着是不是可以把服务总线的技术栈切换到这个上面。今天花了点时间试了试&#xff0c;过程还是比较顺利的&#xff0c;后续…

线性表之单链表

在上一节我们学习了线性表中的顺序表&#xff0c;今天我们来学习一下线性表中的另一种结构——单链表 前言 我们在之前已经初步了解了数据结构中的两种逻辑结构&#xff0c;但线性结构中并非只有顺序表一种&#xff0c;它还有不少兄弟姐妹&#xff0c;今天我们再来学习一下单链…