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

【0】README

1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法(JNI)——调用 java 方法 的基础知识 ;
2) C语言调用java 方法,包括: 静态C 方法 和 非静态C 方法调用 java 方法;
3)为什么要这么做? 因为,本地方法常常需要从 传递给他的对象那里得到某种服务;

4) for source code, please visit : https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/chapter12_61


【1】实例方法

1) 使用如下函数调用, 你可以从C 中调用任何java 方法:

/* call the method */
(*env)->CallXxxxMethod(env, out, id_print, str);
// (*env)->CallXxxxMethod(env, implicit parameter, methodID, explicit parameters);

2)根据方法的返回类型,用Void, Int, Object等来替换Xxx: 就像你需要一个fieldID 来访问某个对象的一个域一样, 你也需要一个方法的ID 来调用方法;
3)调用JNI函数 GetMethodID: 并且提供该类, 方法的名字和方法签名来获得方法ID;

/* get the method ID */
id_print = (*env)->GetMethodID(env, class_PrintWriter, “print”, “(Ljava/lang/String;)V”);
/* call the method */
(*env)->CallVoidMethod(env, out, id_print, str);

4)problem+solution:

  • 4.1)problem:在我们的例子中, 我们想要获得 PrintWriter 类的 print 方法的ID, 但是PrintWriter 类有几个名为 print 的重载方法;
  • 4.2)solution: 基于这个原因, 你还必须提供一个字符串,描述你想要使用的特定函数的参数和返回值;
  • 4.3)看个荔枝: 例如,我们想要使用 void print(java.lang.String) , 正如前一节讲到的那样, 我们必须吧 签名 “混编”为字符串 “(Ljava/lang/String;)V”

5) 下面是进行方法调用的完整代码, 有以下几个 steps:

  • step1)获取隐式参数的类;
  • step2)获取方法ID;
  • step3)进行调用;
/* get the class */class_PrintWriter = (*env)->GetObjectClass(env, out);/* get the method ID */id_print = (*env)->GetMethodID(env, class_PrintWriter, "print", "(Ljava/lang/String;)V");/* call the method */(*env)->CallVoidMethod(env, out, id_print, str);

Attention) 数值型的方法ID 和 域ID 在概念上和反射API 中的 Method 和 Field 对象相似。 你可以使用以下函数在两者之间进行转换;

jobject ToReflectedMethod(JNIEnv* env, jclass class, jmethodID methodID);
// return Method object
methodID From ReflectedMethod(JNIEnv* env, jobject method);
jobject ToReflectedField(JNIEnv* env, jclass class, jfield fieldID);
// returns Field object
fieldID FromReflectedField(JNIEnv* env, jobject field);

6) 看个荔枝(增强型Printf类, 给他增加了一个与 C 函数 fprintf 类似的方法, 也就是说, 它能够在任意 PrintWriter 对象上打印一个字符串。):

javac com/corejava/chapter12_61/Printf3.java
javah com.corejava.chapter12_61.Printf3
mv com_corejava_chapter12_61_Printf3.h Printf3.h
mv Printf3.h com/corejava/chapter12_61/

这里写图片描述

gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ Printf3.c
gcc -shared -fPIC -o libPrintf3.so Printf3.o
这里写图片描述
这里写图片描述

(编译并运行Test java 文件)
javac com/corejava/chapter12_61/Printf3Test.java
java com.corejava.chapter12_61.Printf3Test
这里写图片描述
这里写图片描述


【2】静态方法

1)从本地方法调用java的静态方法,所需要的函数(methods)有:

  • m1) 要用GetStaticMethodID 和 CallStaticXxxMethod 函数;
  • m2)当调用方法时 , 要提供类对象,而不是隐式的参数对象;

2)看个荔枝:让我们从本地方法调用以下静态方法:

System.getProperty(“java.class.path”); // 返回值给出了当前类路径的字符串;

3)对以上代码调用的步骤解析(Analysis):

  • A1)首先: 我们必须要找到用的类。 因为我们没有 System类的对象可供使用, 所以我们使用 FindClass 而非 GetObjectClass:

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

  • A2)接着: 我们需要静态 getProperty 方法的ID。 该方法的编码签名是:

    “(Ljava/lang/String;)Ljava/lang/String;”

  • A3) 既然参数和返回值都是 字符串, 因此,我们这样获取方法ID;

    jmethodID id_getProperty = (*env)->GetStaticMethodID(env, class_System, “getProperty”, “(Ljava/lang/String;)Ljava/lang/String;”)

  • A4)最后: 我们进行调用。 注意,类对象被传递给了 CallStaticObjectMethod 函数:

    jobject obj_ret = (*env)->CallStaticObjectMethod(env, class_System, id_getProperty, (*env)->NewStringUTF(env, “java.class.path”));

4) 该方法的返回值是 jobject 类型的。如果我们想要吧它作为字符串操作, 必须吧他转型为 jstring;


【3】构造器

1)创建新的 java 对象: 本地方法可以通过调用构造器来创建新的java对象;可以调用 NewObject 函数来调用构造器;

jobject obj_new = (*env)->NewObject(env, class, methodID, construction parameters);

2)可以通过指定方法名为 “”: 并指定构造器(返回值为void)的编码签名, 从GetMethodID 函数中获取该调用必须的方法ID;
3)看个荔枝:

const char[] filename = "...";
jstring str_filename = (*env)->NewStringUTF(env, filename);
jclass class_FileOutputStream = (*env)->FindClass(env, "java/io/FileOutputStream");
jmethodID id_FileOutputStream = (*env)->GetMethodID(env, class_FileOutputStream, "<init>", "(Ljava/lang/String;)V");
jobject obj_stream = (*env)->NewObject(env, class_FileOutputStream, id_FileOutputStream, str_filename);

Attention) 构造器的签名接受一个 java.lang.String 类型的参数, 返回类型 为

void;== “(Ljava/lang/String;)V”


【4】替代方法调用

1)有若干种JNI 函数的变体都可以从本地代码调用 java 方法;
2)CallNonvirtualXxxMethod函数:接收一个隐式参数, 一个方法ID, 一个类对象(必须对应于 隐式参数的超类) 和一个显式参数。这个函数将调用指定的类中的指定版本的方法,而不使用 常规的动态调度机制;
3)所有调用函数都有后缀A 和 V 的版本: 用于接收数组中或 va_list 中的显式参数;

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

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

相关文章

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;我在最新…

Shell入门(六)之算术运算

一、数学运算 &#xff08;1&#xff09;原生bash不支持简单的数学运算&#xff0c;但是可以通过其他命令来实现&#xff0c;例如 awk 和 expr&#xff0c;expr 最常用。 &#xff08;2&#xff09;expr 是一款表达式计算工具&#xff0c;使用它能完成表达式的求值操作。 ex…

java数据库编程——执行SQL 语句

【0】README 1&#xff09; 本文文字描述source code 均转自 core java volume 2 &#xff0c; 旨在理解 java数据库编程——执行SQL 语句 的基础知识 &#xff1b; 2&#xff09;for source code, please visit &#xff1a; https://github.com/pacosonTang/core-java-vol…

php cdi_Quarkus的其他(非标准)CDI功能

php cdiQuarkus支持CDI&#xff08;上下文和依赖注入&#xff09;2.0&#xff0c;但并非全部&#xff0c;仅支持最常见的功能。 但是&#xff0c;Quarkus确实包含一些非标准功能&#xff0c;这些功能对于开发人员非常方便&#xff0c;我想在下面的视频中进行展示。 不管您是否…

Shell入门(七)之关系运算

一、关系运算 shell关系运算符只支持数字&#xff0c;不支持字符串&#xff0c;除非字符串的值是数字。 a10 b20 运算符说明举例-eq检测两个数是否相等&#xff0c;相等返回 true。[ $a -eq $b ] 返回 false。-ne检测两个数是否相等&#xff0c;不相等返回 true。[ $a -ne $…

java数据库编程——Insert and Retrieve Images from MySql Table Using Java

【0】README0.1&#xff09;本文翻译自 http://harmeetsingh13.blogspot.jp/2013/03/insert-and-retrieve-images-from-mysql.html【1】正文如下&#xff1a;段1&#xff09;演示 从数据库表中插入和查询出图片。大多数情况下&#xff0c;图片数据都存储在数据库外部的一些文件…

Shell入门(八)之布尔运算

一、常规的布尔运算 常规的布尔运算符有&#xff1a;!、&&、|| 使用语法 ! exp exp && exp exp || exp [[ n op m && a op b]] ... exp为[ n op m ]或test n op m或true或false 二、条件测试的布尔运算 条件测试的布尔运算有&#xff1a;!、…

java switch语句_Java 14:查看更新的switch语句

java switch语句于2020年3月发布的JDK 14带有switch语句的更新版本。 这是JDK 12和JDK 13中的预览功能。 要了解差异&#xff0c;让我们看一个简单的示例。 假设我们要基于DayOfWeek枚举来计算每日工作时间。 使用旧的使用switch语句的方法&#xff0c;我们的解决方案可能如下…

java数据库编程——执行查询操作(一)

【0】README 1&#xff09; 本文部分文字描述和source code 均转自 core java volume 2 &#xff0c; 旨在理解 java数据库编程——执行查询操作 的基础知识 &#xff1b; 2&#xff09; 本文和 java数据库编程——执行查询操作&#xff08;二&#xff09; 是姊妹篇&#xff…

Shell入门(九)之字符串比较

一、字符串比较 字符串比较符&#xff1a;、!、-z、-n、str 实际上&#xff0c;shell不区分数值与字符串类型&#xff0c;数值也可以使用上面比较。 a"mk" b"maokun" 运算符说明举例检测两个字符串是否相等&#xff0c;相等返回 true。[ $a $b ] 返回…