1. 本地代码访问Java代码

  • 在被调用的C/C++函数中也可以反过来访问Java程序中的方法

  • javah 工具生成的C/C++函数声明中,可以看到有两个参数:

JNIEXPORT void JNICALL Java_com_omg_NativeLib_sayHello (JNIEnv *env, jobject jobj){cout << "hello world" << endl;
}

2. JNIEnv 类型

  • JNIENV类型实际上代表了Java环境,通过这个JNIEnv*指针,就可以对Java端的代码进行操作。例如,创建Java类的对象、调用Java对象的方法、获取Java对象的属性等。JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码进行操作。

  • JNIEnv类中有很多函数可以使用

NewObject / NewString / New<TYPE>Array
Get<TYPE>Field / Set<TYPE>Field
GetStatic<TYPE>Field / SetStatic<TYPE>Field
Call<TYPE>Method / CallStatic<TYPE>Method

等许许多多的函数

  • jobject 什么的一个类型呢?

不是静态方式时,传入的是当前关联的类对象

静态方法时,传入当前类的Class对象

3. Java的类型在C/C++中的映射关系

Java类型 本地类型 JNI定义的别名
int long jint / jsize
long __int64 jlong
byte signed char jbyte
boolean unsigned char jboolean
char unsigned short jchar
short short jshort
float float jfloat
double double jdouble
Object _jobject* jobject

4. jclass如何获取

  • 为了能够在C/C++中使用Java类。JNI.h头文件中,专门定义了jclass类型来表示Java中的Class类

  • JNIEnv类中有以下几个函数可以获取jclass:

jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject ojb);
jclass GetSuperClass(jclass obj);

在Java JDK中也有这几个方法

  • FindClass 将会在classpath环境变量下寻找类。传入完整类名,注意包与包之间是使用  “/ “ ,而不是使用 “.“ 来分隔

jclass cls_str = env->FindClass("java/lang/String");

5. 访问Java类中的属性与方法

  • 在C/C++本地代码中访问Java端的代码,一个常见的场景就是获取类的属性和调用类的方法。为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethdID类型来分别代表Java端的属性和方法

  • 在访问,或者设置Java属性的时候,首先就要先在本地代码中获得代表Java属性的jfieldID;然后才能在本地代码中进行Java的属性操作。同样的,在需要调用Java的方法时,也是需要先获取到代表该方法的jmethodID才能进行Java方法调用

使用JNIEnv的

GetFieldID / GetMethodID
GetStaticFieldID / GetStaticMethodID

来取得相应的jfieldID和jmethodID

来看下方法定义

jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig);jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig);
  • GetMethodID也能够获得构造函数的jmethodID。创建一个Java对象时可以调用指定的构造方法,这个将在后面向大家介绍

如:env -> GetMethodID(data_Clazz, "<init>", "()V");

  • 类似Java的发射(Reflect),需要指定类跟属性/方法名来获取相应的jfieldID或者jmethodID。而sign又是什么呢?

6. Sign是什么?

例如:TestNative类中有两个重载的方法

package com.omg;public class TestNative {public void function( int i ){System.out.println("Integer: " + i);}public void function( double d ){System.out.println("double: " + d);}
}

然后再C/C++代码中调用其中的一个function方法的话;

//首先取得要调用的方法所在的类
jclass clazz_TestNative = env->FindClass("com/omg/TestNative");
//获取jmethodID之后才能进行调用
jmethodID id_func = env->GetMethodID(clazz_TestNative, "function", ??);

但是到底取得的是 void function(int i) 方法还是 void function(double d) 方法的jmethodID呢?

这就是sign的作用了,他用于指定要取得的属性/方法的类型。

这里的sign如果指定为"(I)V",则获得的是 void function(int i) 方法的jmethodID;如果指定为"(D)V",则获得的是 void function(double d) 方法的jmethodID

7. sign签名

用来表示要取得的属性/方法的类型

类型 签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object L + 用/分隔包的完整类名 + ;
Array [ + 签名   例如,[I、[Ljava/lang/String;
Method (参数1类型签名 参数2类型签名...)返回值类型签名

8. 使用签名获得属性/方法ID的例子(复杂)

import java.util.Date;public class HelloNative(){public int property;public int function(int foo, Date date, int[] arr){System.out.println("function");}public native void test();
}

test本地方法的实现

JNIEXPORT void Java_Hello_test(JNIEnv* env, jboject ojb) {//因为test不是静态函数,所以传进来的就是调用这个函数的对象jclass hello_clazz = env->GetObjectClass(obj);jfieldID filedID_prop = env->GetFieldID(hello_clazz, "property", "I");jmethodID methodID_func = env->GetMethodID("hello_clazz", "function", "(ILjava/util/Date;[I)I");env->CallIntMethod(obj, methodID_func, 0L, NULL, NULL); //invoke
}

取得的property是int类型的,所以在签名中传入"I"

取得function的ID时

所以在最后得到(ILjava/util/Date;[I)I

9. 使用javap命令来产生签名

  • JDK提供了一个工具来查看一个类的申请,其中就可以设置输出每一个方法/属性的签名

  • java -s -p [full Calss Name]

-s 表示输出签名信息

-p 通-private,输出包括private访问权限的成员信息

分享&在看

JNI:本地代码调用Java代码相关推荐

  1. Qt使用JNI调用Java代码—————附带完整示例

    文章目录 0 背景 1 调用准备 2 调用 2.1 调用方法 2.2 方法签名 2.3 调用示例 2.4 注意事项 3 完整示例代码 3.1 部分代码 3.2 附赠示例 0 背景 在开发Android ...

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

    [0]README 1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法(JNI)--调用 java 方法 的基础知识 : 2) C语言调用java 方法,包括: ...

  3. c 调用java包_C#调用java代码(IKVMC)

    参考资料:https://blog.csdn.net/threadroc/article/details/51406587 参考1:http://www.cnblogs.com/Jack-Blog/p ...

  4. matlab中调用java代码_Matlab中调用第三方Java代码

    在Java中采用Matlab JA Builder可以实现调用m文件,采用这样的方式,可在Matlab的M文件中,直接调用Java类.这种方式可以表示为Java--> Matlab( m, Ja ...

  5. ruby调用java代码

    为什么80%的码农都做不了架构师?>>>    ruby使用rjb调用java代码 require 'rjb'#加载jar包 Rjb::load(classpath = '/home ...

  6. scala调用java代码_scala调用java代码

    scala调用java代码 @(SCALA)[scala] 在scala中调用java代替非常非常简单,直接调用即可 (一)一个简单示例 1.创建一个java类 package com.lujinho ...

  7. scala调用java代码

    scala调用java代码 @(SCALA)[scala] 详细代码请见https://github.com/lujinhong/scalademo 在scala中调用java代替非常非常简单,直接调 ...

  8. python3调用java_Python3-JPype调用Java代码

    原博文 2019-12-31 10:54 − ## JPype调用Java代码 ### 安装所需要的库 ```python pip install JPype1-py3 ``` ### 准备一个jar ...

  9. Python调用Java代码部署及初步使用

    Python调用Java代码部署: jpype下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype 下载的时候需要使用Chrome浏览器进行下载 ...

最新文章

  1. python 全局变量 局部变量
  2. thinkphp导入css失败,为什么用thinkphp总是提示css错误?
  3. mysql主从日志的定期清理
  4. 【转载】Android Animation 简介(官方文档翻译) ---- 翻译的很好!
  5. 三种代理服务器以及反向代理详解
  6. linux vnc的小黑点和鼠标不同步_vnc安装步骤,vnc在Linux中的7个安装步骤
  7. 抽奖系统概率设计_《微博抽奖玄学理论·养号攻略XI》
  8. 最新emoji表情代码大全_三十而已表情包下载-三十而已表情包大全最新下载
  9. 查找入职员工时间排名倒数第三的员工所有信息
  10. python3中的sorted()函数
  11. 我是如何搭建一台家庭NAS的
  12. GSL-蒙特卡洛积分
  13. Longhorn入门级教程!轻松实现持久化存储!
  14. 地理信息系统GIS基础知识
  15. JavaScript之封装Math函数
  16. Windows10系统下电脑时间不对,怎么办?
  17. svn合并时候的诡异事件
  18. 班章管家稳定放心:五万元应该怎样理财?理财产品怎样选?
  19. for循环的正确执行顺序
  20. 裁判文书数据搜索新网站【有法网】

热门文章

  1. 2W公里,就换EBC刹车片?
  2. 飞思卡尔 熟悉小车之 舵机篇
  3. C语言实现LDPC的校验矩阵,LDPC码及其译码实现….doc
  4. 独身主义也不赖:选择不结婚究竟是选择了什么?
  5. 陈峰/何雪松/陈宁客座主编Frontiers口腔微生物组学专刊征稿(IF6)
  6. 针对严峻的网络安全环境,公司就当如何应对?
  7. 文件夹里的文件怎么批量打印呢?
  8. 牛客练习赛66 E-骚区间
  9. 个人形象设计之服装单品的理想搭配
  10. jQuery判断email地址 邮箱地址 email regex