[英]Java: access static final field in JNI
有沒有辦法在JNI中訪問靜態最終字段?
public class TryMe {
public int a = 1;
public final int b = 2;
public static int c = 3;
public static final int d = 4;
}
C ++ JNI代碼:
jclass cls = env->FindClass("my/package/TryMe");
jfieldID a = env->GetFieldID(cls, "a", "I"); //OK
jfieldID b = env->GetFieldID(cls, "b", "I"); //OK
jfieldID c = env->GetStaticFieldID(cls, "c", "I"); //OK
jfieldID d = env->GetStaticFieldID(cls, "d", "I"); //Error!
最后一次調用返回NULL並失敗。 知道為什么嗎?
解決:我被proguard咬了。
我最初認為它可能是Android運行時中的一個錯誤,但事實並非如此。 我相信proguard不知道也不關心JNI所以它決定優化“常數”。 將此添加到proguard.cfg后:
keep class my.package.TryMe {
public static final int d;
}
問題已經消失。
使用javap -p -s TryMe
,變量d
看起來像:
...
public static final int d;
描述符:我
...
?
如果是這樣,那么我真的沒有找到它不應該工作的原因。 你在嘗試這個平台? 我在Arch x86_64上使用以下代碼嘗試了您的示例,它適用於我:
Test.java:
public class Test {
public int a = 1;
public final int b = 2;
public static int c = 3;
public static final int d = 4;
}
ctest.cpp:
#include <iostream>
#include <jni.h>
using namespace std;
int main(){
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString = const_cast<char*>("-Djava.class.path=/home/fishi/Workspace/tmp/");
vm_args.version = JNI_VERSION_1_8;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_FALSE;
/* Create the Java VM */
int res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
if (res == JNI_ERR){
cout << "Fail: Unable to load JVM \t Exit" << endl;
return 1;
}
else if (res == JNI_OK){
cout << "CreateVM:\t\tJVM loaded successfully!" << endl;
}
/* Find class and static field */
jclass cls = env->FindClass("Test");
if(cls == NULL)
{
cout << "FindClass:\t\tCould not load class!" << endl;
return 1;
}
else
{
cout << "FindClass:\t\tLoaded class successfully!" << endl;
}
jfieldID field = env->GetStaticFieldID(cls, "d", "I");
if(field == NULL)
{
cout << "GetField:\t\tError!" << endl;
return 1;
}
cout << "Success" << endl;
}
Makefile文件:
build-jni:
g++ -g -I/usr/lib/jvm/java-8-openjdk/include/ -I/usr/lib/jvm/java-8-openjdk/include/linux/ -L/usr/bin/java -L/usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ ctest.cpp -ljvm -o ctest
run-jni:
LD_LIBRARY_PATH=/usr/bin/java:/usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ ./ctest
輸出:
$ make run-jni
LD_LIBRARY_PATH = / usr / bin / java:/ usr / lib / jvm / java-8-openjdk / jre / lib / amd64 / server / ./ctest
CreateVM:JVM加載成功!
FindClass:已成功加載類!
成功
希望這在某些方面有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.