java JNI GetMethodID不适用于内部类的构造函数
我有一个带有私有子类的类。我想在JNI包装器中创建该子类的一个实例并返回它。我在谷歌上搜索并试图让它工作,但没有成功(methodID为null)。有什么建议吗
JNIEXPORT jobject JNICALL Java_some_Class_some_Jni_Method(JNIEnv *env, jobject this) {
jclass cls = (*env)->FindClass(env, "someClass$someSubclass");
if (cls == NULL)
printf("jclass error.");
jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "()V"); // -> problem!
if (methodID == NULL)
printf("jmethodID error.");
jobject obj = (*env)->NewObject(env, cls, methodID);
if (obj == NULL)
printf("jobject error.");
return obj;
}
EDIT1:添加类定义:
public class someClass
{
private class someSubclass {
public someSubclass() {
}
...
}
...
}
EDIT2:我发现GetMethodID签名中需要父类,所以在我的示例中:jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "(LsomeClass;)V");
但现在我得到了NewObject函数的异常访问冲突
EDIT3:我还需要添加调用类object/指向NewObject函数的指针:jobject obj = (*env)->NewObject(env, cls, methodID, this);
嵌套类的构造函数现在被正确调用
# 1 楼答案
GetMethodID签名中需要父类,因此在我的示例中:
jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "(LsomeClass;)V");
我还需要向NewObject函数添加调用类对象/指针:
jobject obj = (*env)->NewObject(env, cls, methodID, this);
# 2 楼答案
请注意@user2340939的答案:
https://stackoverflow.com/a/25363953/6655884
由于java认为我的第一个参数是类父级,所以我在弱本地引用方面出错
如果可以,可以将内部类设置为静态,这样就不需要在构造函数中放置父类签名,也不需要在创建对象时在构造函数中传递父类
# 3 楼答案
我想为这个问题提供一个更复杂的答案。下面是我正在用JNI做的一些实验的简化版本,以学习如何使用它。这个例子更多的是探索如何使用JNI访问对象和字段,而不是推荐使用JNI
此外,Java源代码经过了轻微修改,删除了大量处理其他JNI使用的其他源代码。然而,这应该是一个起点。JNI有一些最佳实践,比如缓存字段标识符,在本例中被忽略。这里是some best practices using JNI from IBM
在这个源代码示例中,想法是有一个类
helloworld
,它包含一个内部类ExportedFuncs
,它将有各种方法作为从动态链接库(DLL)导出的一组本机C函数的接口。这个内部类将有自己的内部类ExportedData
,这将是一个只包含数据的类创建
ExportedFuncs
对象时,它将使用JNI执行本机调用,以获取ExportedData类的实例JNI需要一个完全限定的类名
请注意,在下面的JNI原生C源代码中,
GetFieldID()
和FindClass()
函数都使用完全限定的类名"Lhelloworld$ExportedFuncs$ExportedData;"
,它的内部类用美元符号($)分隔GetMethodID()
函数必须包含任何内部类的父类。如果正在查找的方法位于主类helloworld
内,则调用如下所示:然而,由于我们想要构造一个内部类的内部类,我们需要为我们想要构造的内部类指定父类,如下所示:
另一点是
ExportedData
类的构造函数是默认构造函数,它不接受任何参数。如果有参数,则需要将这些参数添加到GetMethodID()
函数调用中使用的方法签名中。因此,如果正在使用一个采用int
的构造函数,那么签名将看起来像"(Lhelloworld$ExportedFuncs;I)V"
带有内部类的Java和JNI的简单示例
假设一个简单的示例Java类带有一个封装的内部类。这个例子有一个内部类,它有一个内部类
JNI原生C函数看起来
本机JNI代码的函数签名是使用
helloworld
类上的javah
实用程序生成的。您可能还会发现javap
实用程序的输出也很有用顺便说一句,我觉得有趣的是,内部类的本机方法的名称有五位数的数字字段00024,这是ANSI/ASCII表中美元符号($)的十六进制。美元符号用于JNI函数(如
GetFieldID()
)中使用的完全限定名中的内部类的分隔符在这个人为设计的示例中,我没有使用包,因此本机C函数名没有包组件。通常会有。我的一个问题是,命名约定中使用的函数名长度的限制是什么
# 4 楼答案
user2340939的答案帮助我找到正确的方法,用内部类的整数参数构造一个新对象。 这是我的报酬
JAVA
CPP
对于NewObject,不是一个内部类
但我仍然想知道哪个文档告诉内部类的NewObject API必须添加parenter类