前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JNI:本地代码调用Java代码

JNI:本地代码调用Java代码

作者头像
BUG弄潮儿
发布2022-03-08 10:49:00
1.6K0
发布2022-03-08 10:49:00
举报
文章被收录于专栏:JAVA乐园

1. 本地代码访问Java代码

  • 在被调用的C/C++函数中也可以反过来访问Java程序中的方法
  • javah 工具生成的C/C++函数声明中,可以看到有两个参数:
代码语言:javascript
复制
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类中有很多函数可以使用
代码语言:javascript
复制
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:
代码语言:javascript
复制
jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject ojb);
jclass GetSuperClass(jclass obj);

在Java JDK中也有这几个方法

  • FindClass 将会在classpath环境变量下寻找类。传入完整类名,注意包与包之间是使用 “/ “ ,而不是使用 “.“ 来分隔
代码语言:javascript
复制
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的

代码语言:javascript
复制
GetFieldID / GetMethodID
GetStaticFieldID / GetStaticMethodID

来取得相应的jfieldID和jmethodID

来看下方法定义

代码语言:javascript
复制
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类中有两个重载的方法

代码语言:javascript
复制
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方法的话;

代码语言:javascript
复制
//首先取得要调用的方法所在的类
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的例子(复杂)

代码语言:javascript
复制
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本地方法的实现

代码语言:javascript
复制
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访问权限的成员信息

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 本地代码访问Java代码
  • 2. JNIEnv 类型
  • 3. Java的类型在C/C++中的映射关系
  • 4. jclass如何获取
  • 5. 访问Java类中的属性与方法
  • 6. Sign是什么?
  • 7. sign签名
  • 8. 使用签名获得属性/方法ID的例子(复杂)
  • 9. 使用javap命令来产生签名
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档