【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 中的显式参数;

本地方法(JNI)——调用 java 方法相关推荐

  1. c 调用java post方法_C#调用Java方法(详细实例)

    C#可以直接引用C++的DLL和转换JAVA写好的程序.最近由于工作原因接触这方面比较多,根据实际需求,我们通过一个具体例子把一个JAVA方法转换成可以由C#直接调用的DLL C#调用c++ C#调用 ...

  2. python调用java方法_python调用Java方法传入HashMap ArrayList

    1.Java代码: package com; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap ...

  3. java方法的构造,java方法与构造

    public class StaticClass { static int i = 50; int y; // 构造只能有访问修饰符public.protected.private 修饰 (访问修饰符 ...

  4. JNI调用native方法出现 java.lang.UnsatisfiedLinkError: XXXclass.XXXmethod()异常的解决办法

    JNI调用native方法出现 java.lang.UnsatisfiedLinkError: XXXclass.XXXmethod()异常的解决办法 参考文章: (1)JNI调用native方法出现 ...

  5. 【Android NDK 开发】JNI 方法解析 ( C/C++ 调用 Java 方法 | 函数签名 | 调用对象方法 | 调用静态方法 )

    文章目录 I . 调用 Java 方法流程 II . 获取 jclass 对象 ( GetObjectClass ) III . 获取 jclass 对象 ( FindClass ) IV . JNI ...

  6. JNI基础 c语言调用java方法

    利用c语言调用java无参的方法 java方法 com.example.jniparsedata.ParseData类中的方法     //打印     public void sayHelloFro ...

  7. android jni 结构体_Android应用开发Android JNI-c/c++调用java方法

    本文将带你了解Android应用开发Android JNI-c/c++调用java方法,希望本文对大家学Android有所帮助. " Android   JNI-c/c++调用java方法, ...

  8. c jni 调用java_如何使用JNI从C调用JAVA方法

    我想使用JNI( Java Native Interface)来调用特定的java setter方法,将short []缓冲区作为参数传递给它. Java方法实现如下: public void set ...

  9. Android-jni(10)-jni调用java父类方法

    jni调用java父类方法,在知道这个之后,我感觉jni能做的事真是厉害.我们一起来看看它与java的不同 一. jni调用java父类方法 先做个准备: 准备一个Java父类和子类,People和B ...

最新文章

  1. 手动创建servlet
  2. STM32F407VG uCOS-II2.91 IAR工程 以及uCOS使用库编译的方法
  3. synchronized,ReetrantLock与volatile(二)
  4. RHEL7 -- 修改主机名
  5. Window插件获取窗口坐标
  6. 永别了!2200元,老外眼中的2200元神机缺货数月后下架
  7. oracle数据库静态启动,ORACLE数据库的连接
  8. 如何防止softmax函数上溢出(overflow)和下溢出(underflow)
  9. MFC中给对话框重绘边框
  10. php 识别图片指定区域,简单实现图片局部识别的方法
  11. JSTL 核心标签库 使用(C标签)
  12. 【机器学习系列】变分推断第二讲:基于Mean Field的变分推断解法
  13. ISO7637-2瞬态浪涌波形详解
  14. C++中set用法详解
  15. [JZOJ4058]【JSOI2015】子集选取
  16. 【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
  17. 百度卫星地图无法使用鼠标绘制工具的问题简单解决方案
  18. Moto android系統 流量,天翼旗舰 摩托罗拉Droid X ME811评测
  19. 绝对布局AbsoluteLayout学习笔记
  20. axure读取服务器文件,Axure教程|云盘案例原型:文件管理

热门文章

  1. 牛客题霸 [子数组的最大累加和问题] C++题解/答案
  2. luogu P4240 毒瘤之神的考验(莫比乌斯反演+递推前缀和+数论分块)
  3. Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round) 题解
  4. P3746 [六省联考 2017] 组合数问题(倍增、dp)
  5. CF388D-Fox and Perfect Sets【dp,线性基】
  6. jzoj3058-火炬手【高精度,暴力】
  7. ssl初一组周六模拟赛【2018.4.14】
  8. CSP-S 2021 退役记
  9. 【区间DP】甲虫(luogu 4870)
  10. 10、mybatis中缓存的使用