java - 具有原始类型的 JNI GetObjectClass
问题描述
我有以下 JNI/JVMTI 代码:
jfieldID field = ...;
jobject fieldValue = (*jni_env)->GetObjectField(jni_env, jObjectInstance, field);
jclass fieldClass = (*jni_env)->GetObjectClass(jni_env, fieldValue);
char* signature_ptr;
char* generic_ptr;
(*jvmti_env)->GetClassSignature(jvmti_env, fieldClass, &signature_ptr, &generic_ptr);
此代码适用于 long字段是引用类型(java.lang.Object 和子类型)。如果field是原始类型,它会在尝试执行GetObjectClass时使 JVM 崩溃。
我的问题是:如何使用field和fieldValue来确定它是否是原始类型以及是否是原始类型,是哪一个(int、long、boolean 等)?
我是 JNI/JVMTI 的新手,所以如果答案很明显,请多多包涵。
谢谢!
解决方案
调用which 不是对象类型是非法GetObjectField
的。jfieldID
对于原始字段,您需要调用其他Get[Type]Field
函数之一,其中[Type]
是Int
// Long
/ Boolean
etc。
既然你已经有了jvmti_env
,查找jfieldID
类型的最简单方法是调用 JVM TI GetFieldName函数。除其他外,它返回字段签名,即字段的类型。
唯一的问题是jfieldID
应该始终伴随jclass
- 字段的持有者,因为字段 ID 是相对于特定类的。通常,当您获得 时jfieldID
,您已经知道它的持有者类。如果没有,在您的情况下,您有jObjectInstance
- 一个具有此字段的对象,因此可以使用 JNI GetObjectClass函数从实例派生持有者类。
jclass fieldHolder = (*jni_env)->GetObjectClass(jni_env, jObjectInstance);
char* name;
char* signature;
if ((*jvmti_env)->GetFieldName(jvmti_env, fieldHolder, field, &name, &signature, NULL) == 0) {
switch (signature[0]) {
case 'I':
// int
break;
case 'J':
// long
break;
...
case 'L':
// object
break;
case '[':
// array
break;
}
(*jvmti_env)->Deallocate(jvmti_env, signature);
(*jvmti_env)->Deallocate(jvmti_env, name);
}
推荐阅读
- python - 如果在运行 python 脚本之前打开了串行端口,我该如何关闭它?
- google-calendar-api - 服务帐户无法在 laravel PHP 中的日历 API 上没有全域授权委托的情况下邀请与会者
- leaflet - 传单markerclusterGroup layerGroup
- ruby-on-rails - 无法从本地计算机在远程服务器上运行捆绑命令
- angular - 在 Angular/Firestore 中使用 Stripe 支付
- sql - 使用 JSON_VAL 原因从 JSON 字符串中获取属性“
在使用的上下文中无效”错误 - javascript - 线性数学变换与 scaleLinear D3 函数的关系
- vue.js - 组件中的 Nuxt 内容异步获取
- laravel - 如何在 laravel 的 textarea 中换行,然后通过 foreach 循环回显?
- python - 在 Python 数据框列中滑动子字符串的窗口