网站首页 > java教程 正文
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访问权限的成员信息
猜你喜欢
- 2024-11-24 如何追踪Java对象的访问?
- 2024-11-24 java项目本地部署JeecgBoot低代码开发平台Vue3版系统源码
- 2024-11-24 windows本地通过Java API方式监控远程Yarn
- 2024-11-24 Java项目本地部署搭建实战SpringBoot高校宿舍管理系统源码
- 2024-11-24 Java项目本地搭建宝塔部署AI物品分类识别管理系统uniapp源码
- 2024-11-24 java本地线程ThreadLocal
- 2024-11-24 Java类加载过程
- 2024-11-24 Java项目本地部署宝塔搭建实战-医院HIS系统源码
- 2024-11-24 在Java程序中监听mysql的binlog
- 2024-11-24 快来试试这款一行代码实现多平台文件存储的工具!
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)