本地方法(JNI)——访问域+字符串参数

【0】README

1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法(JNI)——访问域+字符串参数 的基础知识 ;
2) for source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/chapter12_4


【1】本地方法(JNI)——访问域相关

0)相关JNI函数定义:

  • 0.1)GetDoubleField 和 SetDoubleField函数: 获取和设置fieldID 的值, 因为salary是 double 类型的;
/* get the field value */ jdouble salary = (*env)->GetDoubleField(env, obj, id_salary);   salary += increment;   /* set the field value */(*env)->SetDoubleField(env, obj, id_salary, salary);
  • 0.2)对于其他类型可以使用的函数有: GetIntField/SetIntField, GetObjectField/SetObjectField;其通用语法是: (干货——这叫调用特殊的JNI函数来获取和设置数据的值)
x=(*env)->GetXxxField(env, this_obj, fieldId);
(*env)->SetXxxField(env, this_obj, fieldID, x);
  • 0.3)这里 fieldID: 他是一个特殊类型 jfieldID 的值, jfieldID 标识结构中的一个域, 而 Xxx 代表java 数据类型(Object, Boolean, Byte 或其他);
  • 0.4)为了获得 fieldID, 必须先获得一个表示类的值, 有两种方法可以实现此目的。

    • 0.4.1)GetObjectClass函数:可以返回任意对象的类; 如,

      jclass class_Employee = (*env)->GetObjectClass(env, obj);

    • 0.4.2)FindClass函数: 可以让你以字符串形式来指定类名(要用 / 代替句号作为包名间的分隔符):

      jclass class_string = (*env)->FindClass(env, “java/lang/String”);

  • 0.5)之后可以使用GetFieldId 函数: 获得fieldId, 必须提供域的名字, 他的签名 和 他的类型编码;

    jfield id_salary = (*env)->GetFieldId(env, class_Employee, “salary”, “D”); // 字符串D 表示 double;

1)our destination(调用 Employee类的本地方法)
这里写图片描述

2) detailed steps:

  • step1) javah 导出类的头文件;
    这里写图片描述

  • step2)拷贝上述头文件中 raiseSalary的函数原型 到新建的 Employee.c中, 并提供 raiseSalary 的 C 语言实现;

    
    #include "com_corejava_chapter12_4_Employee.h"#include <stdio.h>JNIEXPORT void JNICALL Java_com_corejava_chapter12_14_Employee_raiseSalary(JNIEnv * env, jobject obj, jdouble increment)
    {/* get the class == Employee 类 */jclass class_Employee = (*env)->GetObjectClass(env, obj);/* get the field ID == salary域标识符 */jfieldID id_salary = (*env)->GetFieldId(env, class_Employee, "salary", "D");// attention jfieldID not ifieldId ,  GetFieldId not GetFieldId/* get the field value == salary 域值*/jdouble salary = (*env)->GetDoubleField(env, obj, id_salary);salary += increment;/* set the field value == salary 域值设置器 */(*env)->SetDoubleField(env, obj, id_salary, salary);
    }
  • 这里写图片描述

  • Warning)

    • w1)类引用只在本地方法返回之前有效;因此,不能在你的代码中缓存GetObjectClass 的返回值;
    • w2)不要将类引用保存下来以供以后的方法调用重复使用;
    • w3)必须在每次执行本地方法时都调用 GetObjectClass, 如果你无法忍受这一点, 必须调用 NewGlobalRef 来锁定该引用;

      static jclass class_X=0;
      static jfieldId id_a;

      if(class_X == 0)
      {
      jclass cx = (*env)->GetObjectClass(env, obj); // env == 函数列表指针;
      class_X = (*env)->NewGlobalRef(env, cx); // 锁定引用;
      id_a = (*env)->GetFieldId(env, cls, “a”, “……”);
      }

    • w4) 现在,你可以在后买你的调用中使用类引用和域ID了。 当你结束对类的使用时, 务必调用:

      (*env)->DeleteGlobalRef(env, class_X);

  • step3) 编译 Employee.c 文件,并编译到 动态装载库 libEmployee.so;
    这里写图片描述

  • step4)将动态装载库拷贝到 java.lib.path 路径下, 并运行javaTest :
    这里写图片描述
    这里写图片描述


【2】访问静态域

1)访问静态域和访问非静态域类似。你要使用 GetStaticFieldID 和 GetStaticXxxField/SetStaticXxxField 函数。
2) 它们几乎与非静态的情形一样,只有两个区别(Distinctness):

  • D1)由于没有对象, 必须使用FindClass 代替 GetObjectClass 来获得类引用;
  • D2)访问域时, 要提供类而非实例对象;

3)看个荔枝: 下面给出的是怎样得到 System.out 的 引用代码:

/*  get the class */
jclass class_System = (*env)->FindClass(env, "java/lang/System"); 
/* get the field ID */
jfieldID id_out = (*env)->GetStaticFieldID(env, class_System, "out", "Ljava/io/PrintStream;");
/*  get the field value */
jobject obj_out = (*env)->GetStaticField(env, class_System, id_out);

【3】本地方法(JNI)——字符串参数(本节没有实际代码,故仅供了解吧,有机会再更新上代码)

(干货——字符串参数讲的是,怎样把字符串传入或传出本地方法)
1)problem+solution:

  • 1.1)problem: java中的字符串是 UTF-16 编码点的序列, 而 C 的字符串则是以 null 结尾的字节序列, 所以在这两种语言中的字符串是很不一样的;
  • 1.2)solution: java本地接口 有两组操作字符串的函数: 一组是把 java 字符串转换为 “改良的UTF-8”字节序列; 另一组将他们转换为 UTF-16 数值的数组, 也就是说转换为 jchar 数组;

Attention) 标准的UTF-8编码和 改良的UTF-8编码的区别:

  • A1) 标准UTF-8编码: 这些字符编码是4字节序列;
  • A2)改良的UTF-16 编码: 在改良的编码中, 这些字符首先被编码为 一对 UTF-16编码的替代品, 然后再对 每个替代品用 UTF-8 编码,总共产生6字节编码;
  • A3) 这有点笨拙, 但这是个历史原因造成的意外, 编写java 虚拟机规范的时候 Unicode 还局限在 16位;

2) jstring类型: 带有字符串参数的本地方法实际上都要接受一个 jstring 类型的值, 而带有字符串参数返回值的本地方法必须返回一个 jstring 类型的值。 JNI 函数将读入并构造出这些 jstring 对象;
3)看个荔枝(下面是对 NewStringUTF 函数的一个调用):

 JNIEXPORT jstring JNICALL Java_HelloNative_getGreeting(JNIEnv *env, jclass cl)
{jstring jstr;char greeting[] = "hello, native method. \n";jstr = (*env)->NewStringUTF(env, greeting);return jstr;
}

4) env指针: 所有对 JNI 函数的调用都使用到了 env 指针, 该指针是每个本地方法的第一个参数。

  • 4.1) env 指针定义: env指针是 指向函数指针表的指针(参见图12-2), 所以,你必须在每个JNI 调用前面加上 (*env)-> , 以便实际上解析对 函数指针的引用。 而且,env 是每一个JNI 函数的第一个参数;* (干货—— env 指针定义)
    这里写图片描述

5)NewStringUTF函数: 该函数从包含ASCII 字符的字符数组,或者更一般的“改良的UTF-8”编码的字节序列,创建一个新的 jstring;

  • 5.1) GetStringUTFChars 函数: 而读取现有 jstring 对象的内容,需要使用 GetStringUTFChars 函数, 该函数返回指向描述字符串的 “改良UTF-8”字符的 const jbyte* 指针;
  • 5.2)注意, 具体的虚拟机可以为其内部的字符串表示自由选择编码机制, 所以,你可以得到实际的 java 字符串的字符指针;
  • 5.3)另一方面: 如果虚拟机使用 UTF-16 或 UTF-32 字符作为其内部字符串的表示, 那么该函数会分配一个新的内存块来存储等价的 “改良的UTF-8”编码字符;

6) 垃圾回收器: 虚拟机必须知道你何时使用完字符串, 这样他就能够进行垃圾回收。垃圾回收器是在一个 独立线程中运行的, 他能够中断本地方法的执行; 基于这个原因, 你必须调用ReleaseStringUTFChars 函数;
7)另外: 可以通过调用 GetStringRegion 或 GetStringUTFRegion 方法来提供你自己的缓存, 以存放字符串的字符;
8)GetStringUTFLength函数:返回字符串的 “改良的UTF-8”编码所需的字符个数;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

aws上负载均衡器标组端口_AWS CloudFormation:目标组没有关联的负载均衡器

aws上负载均衡器标组端口昨天&#xff0c;我使用AWS CloudFormation模板最终创建了ECS服务&#xff08;Fargate类型&#xff09;&#xff0c;还创建了包括应用程序负载均衡器&#xff0c;目标组和IAM角色的资源。 创建堆栈时&#xff0c;出现以下错误&#xff1a; 具有target…

Spring入门(二)之下载与安装

一、Spring下载 参考其他博客&#xff1a;http://www.cnblogs.com/yjmyzz/p/3847364.html或http://blog.csdn.net/xinzhujin/article/details/54319043 Spring下载地址为&#xff1a;http://repo.spring.io/release/org/springframework/spring/ 二、压缩包下的SpringFramewo…

HttpClient 4 API –获取状态代码-getStatusLine()。getStatusCode()示例

在HttpClient API中获取状态代码的快速指南。 getStatusLine&#xff08;&#xff09;。getStatusCode&#xff08;&#xff09;示例和相关的错误。 1.简介 在这个非常快速的教程中&#xff0c;我将展示如何使用HttpClient 4获取和验证HTTP响应的StatusCode。 2. Maven依赖 要…

Spring入门(三)之IoC

一、IoC定义IoC&#xff0c;即控制反转。开发者在使用类的实例之前&#xff0c;需要先创建对象的实例。但是IoC将创建实例的任务交给IoC容器&#xff0c;这样开发应用代码时只需要直接使用类的实例&#xff0c;这就是IoC。在讨论控制反转这个概念的过程中&#xff0c;Martin Fo…

云服务器的优点和缺点_为什么要使用云计算? 的优点和缺点

云服务器的优点和缺点在过去的几年中&#xff0c;云计算一直是IT界的热门话题。 像许多事物一样&#xff0c;当它第一次出现时&#xff0c;很多人都将其视为下一件大事&#xff0c;但是云计算确实达到了期望&#xff0c;并真正改变了当今信息技术业务部门的运作方式。 云计算由…

本地方法(JNI)——编码签名

【0】README 1&#xff09; 本文部分文字描述 转自 core java volume 2 &#xff0c; 旨在理解 本地方法&#xff08;JNI&#xff09;——编码签名 的基础知识 &#xff1b; 【1】编码签名相关 1&#xff09; 混编规则&#xff1a;为了访问实例域和调用用 java 定义的方法&a…

Shell入门(一)之简介

一、Shell 定义 &#xff08;1&#xff09;Shell Shell是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。 &#xff08;2&#xff09;Shell 脚本&#xff08;shell script&#xff09; Shell 脚本…

aws dynamodb_使用适用于Java 2的AWS开发工具包的AWS DynamoDB版本字段

aws dynamodb将任何实体上的版本属性保存到 AWS DynamoDB数据库&#xff0c;它只是表示已修改实体次数的数字表示。 首次创建实体时&#xff0c;可以将其设置为1&#xff0c;然后在每次更新时递增。 好处是立竿见影的-指示实体已被修改的次数&#xff0c;可用于审核实体。 此…

本地方法(JNI)——调用 java 方法

【0】README 1&#xff09; 本文部分文字描述 转自 core java volume 2 &#xff0c; 旨在理解 本地方法&#xff08;JNI&#xff09;——调用 java 方法 的基础知识 &#xff1b; 2&#xff09; C语言调用java 方法&#xff0c;包括&#xff1a; 静态C 方法 和 非静态C 方法…

Shell入门(二)之变量

一、shell变量类型 shell变量一般只有两种类型&#xff1a;数值型与字符串型。 运行shell时&#xff0c;会同时存在三种变量&#xff1a; 1) 局部变量 局部变量在脚本或命令中定义&#xff0c;仅在当前shell实例中有效&#xff0c;其他shell启动的程序不能访问局部变量。 …

aws部署ssh_将Quarkus应用程序部署到AWS Elastic Beanstalk

aws部署sshElastic Beanstalk允许在AWS云中部署和管理应用程序&#xff0c;而无需了解运行这些应用程序的基础架构。 使用Elastic Beanstalk&#xff0c;您可以运行可处理HTTP请求的网站&#xff0c;Web应用程序或Web API&#xff0c;但也可以运行辅助应用程序以运行长任务。 …

本地方法(JNI)——访问数组元素+错误处理

【0】README 1&#xff09; 本文文字描述 均转自 core java volume 2 &#xff0c; 旨在理解 本地方法&#xff08;JNI&#xff09;——访问数组元素错误处理 的基础知识 &#xff1b; 2&#xff09;for source code, please visit : https://github.com/pacosonTang/core-j…

Shell入门(三)之字符串

一、单引号 字符串可以用单引号&#xff0c;也可以用双引号&#xff0c;也可以不用引号。单双引号的区别跟PHP类似。 单引号不存在转义字符&#xff0c;如&#xff1a;\a&#xff0c;\n&#xff0c;$abc #!/bin/bash aabc b${a}bc; echo $b; #结果为&#xff1a;${a}bc…

tms tck_在雅加达EE TCK中使用Arquillian的可能方法

tms tck最近&#xff0c;我们讨论了如何创建独立的Jakarta Batch测试套件&#xff08;TCK&#xff09;。 对于大多数提交者而言&#xff0c;使用Arquillian将测试从实现中如何执行抽象化是很自然的。 但是Romain提出了一个有趣的想法&#xff0c;即使用纯JUnit5引起了我的思考。…

本地方法(JNI)——使用调用API

【0】README 1&#xff09; 本文文字描述source code 均转自 core java volume 2 &#xff0c; 旨在理解 本地方法&#xff08;JNI&#xff09;——使用调用API 的基础知识 &#xff1b; 2&#xff09; for source code, please visit : https://github.com/pacosonTang/cor…

Shell入门(四)之数组

一、一维数组 bash支持一维数组&#xff08;不支持多维数组&#xff09;&#xff0c;并且没有限定数组的大小。 类似与C语言&#xff0c;数组元素的下标由0开始编号。 二、定义数组 在Shell中&#xff0c;用括号来表示数组&#xff0c;数组元素用"空格"符号分割开。…

aws cloud map_销毁AWS资源:Cloud-Nuke还是AWS-Nuke?

aws cloud map因此&#xff0c;您在开发帐户上工作&#xff0c;并且Terraform陷入了一个循环&#xff0c;难道不让您轻易销毁剩余资源吗&#xff1f; 进入nuke CLI的世界&#xff01; 在撰写本文时&#xff0c;我使用的是v0.1.16版本 用Go语言编写的《 Gruntwork》不会破坏掉…

mysql error 1045 的解决方法

【0】README 1&#xff09;以下是 解决方法的steps&#xff1a; step1&#xff09;点击 skip 和 cancel 退出 mysql 配置 step2&#xff09; 重启mysql server config wizard&#xff0c; 然后 remove instance step3&#xff09; 随后卸载mysql&#xff08;通过360或 …

Shell入门(五)之参数

一、Shell 传递参数 在执行 Shell 脚本时&#xff0c;向脚本传递参数&#xff0c;脚本内获取参数的格式为&#xff1a;$n。n 代表一个数字&#xff0c;0为执行文件名&#xff0c;1 为执行脚本的第一个参数&#xff0c;2 为执行脚本的第二个参数&#xff0c;以此类推 比如&…

openj9下载_Quarkus on OpenJ9 JVM和资源消耗

openj9下载除了本机模式&#xff0c;Quarkus在JVM模式下也能很好地运行&#xff0c;这有其自身的优势。 您可以使用替代的JVM&#xff0c;例如OpenJ9&#xff0c;它可以更好地消耗资源。 在下面的视频中&#xff0c;我将展示交换JVM有多么容易。 在视频中&#xff0c;我在最新…