use*_*939 8 c java java-native-interface constructor wrapper
我有一个私有子类.我想在JNI包装器中创建该子类的实例并返回它.我用Google搜索并尝试使其工作但没有成功(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;
}
Run Code Online (Sandbox Code Playgroud)
EDIT1:添加类定义:
public class someClass
{
private class someSubclass {
public someSubclass() {
}
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
EDIT2:好的我发现你需要GetMethodID签名中的父类,所以在我的例子中: jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "(LsomeClass;)V");
但现在我使用NewObject函数获得EXCEPTION_ACCESS_VIOLATION.
EDIT3:我还需要为NewObject函数添加调用类对象/指针: jobject obj = (*env)->NewObject(env, cls, methodID, this);
现在可以正确调用嵌套类的构造函数.
您需要 GetMethodID 签名中的父类,因此在我的示例中:
jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "(LsomeClass;)V");
而且我还需要向 NewObject 函数添加调用类对象/指针:
jobject obj = (*env)->NewObject(env, cls, methodID, this);
我想为这个问题提供一个更复杂的答案.以下是我正在与JNI一起学习如何使用它的一些实验的简化版本.此示例更多的是探索如何使用JNI访问对象和字段,而不是作为使用建议.
此外,Java源代码稍作修改,删除了其他一些处理其他JNI用途的源代码.然而,这应该提供一个起点.JNI有一些最佳实践,例如缓存字段标识符,在此示例中将被忽略.以下是使用IBM的JNI的一些最佳实践.
在这个从该源获取的示例中,想法是拥有一个helloworld包含内部类的类,该类ExportedFuncs具有各种方法,这些方法充当从动态链接库(DLL)导出的一组本机C函数的接口.这个内部类反过来会有自己的内部类,ExportedData它将是一个仅数据类.
当ExportedFuncs创建对象时,它会使用JNI来获得ExportedData类的实例做一个本地电话.
假设一个带有封装内部类的简单示例Java类.此示例具有内部类,该内部类具有内部类.
public class helloworld {
private class ExportedFuncs
{
// declare our private, data only class with some fields
private class ExportedData
{
int theInt;
String theString;
}
public native ExportedData getExportedData();
ExportedData theExportedData;
// constructor for the ExportedFuncs class which gets a copy of the data
ExportedFuncs()
{
theExportedData = getExportedData(); // get an object through native method
}
}
ExportedFuncs myExportedFuncs = new ExportedFuncs();
// .... other fields and methods of the helloworld class follows
}
Run Code Online (Sandbox Code Playgroud)
JNI本机C函数看起来
JNIEXPORT jobject JNICALL Java_helloworld_00024ExportedFuncs_getExportedData (JNIEnv *env, jobject obj)
{
jfieldID fid = (*env)->GetFieldID(env, (*env)->GetObjectClass(env, obj), "theExportedData", "Lhelloworld$ExportedFuncs$ExportedData;");
jobject newObj = 0;
jclass cls = (*env)->FindClass(env, "Lhelloworld$ExportedFuncs$ExportedData;");
// Get the Method ID of the constructor for this inner class.
// There are two things to notice about this GetMethodID() function call.
// First, the constructor is requested by specifying the special string "<init>"
// Second, the signature of the constructor includes the enclosing class in the signature.
// Also there are no arguments for this constructor. if there were then they would need to be included between the parenthesis
// for example "(Lhelloworld$ExportedFuncs;I)V" for a single int arg.
jmethodID midInit = (*env)->GetMethodID(env, cls, "<init>", "(Lhelloworld$ExportedFuncs;)V");
if (NULL == midInit) return NULL;
// Call the class constructor to allocate a new instance. the default constructor has no arguments.
newObj = (*env)->NewObject(env, cls, midInit);
// now lets set some values in our new object and return it.
if (newObj) {
jfieldID fidAge = (*env)->GetFieldID (env, cls, "theInt", "I");
(*env)->SetIntField (env, newObj, fidAge, 127);
}
return newObj;
}
Run Code Online (Sandbox Code Playgroud)
使用该类javah上的实用程序生成本机JNI代码的函数签名helloworld.您也可以从javap实用程序中找到有用的输出.
顺便说一下,我觉得有趣的是,内部类的本机方法的名称具有五位数字字段00024,这是ANSI/ASCII表中美元符号($)的十六进制.美元符号用于JNI函数中使用的完全限定名称的内部类的分隔符,例如GetFieldID().
我没有在这个人为的示例中使用包,因此本机C函数名称没有包组件.通常会有.我遇到的问题是命名约定所使用的函数名长度的限制是什么.
请注意,函数GetFieldID()和FindClass()函数都使用完全限定的类名,"Lhelloworld$ExportedFuncs$ExportedData;"其内部类由美元符号($)分隔.
该GetMethodID()函数必须包含任何内部类的父类.如果正在查找的方法是在主类中helloworld,那么调用将如下所示:
jmethodID midInit = (*env)->GetMethodID(env, cls, "<init>", "()V");
Run Code Online (Sandbox Code Playgroud)
但是,由于我们想要构造内部类的内部类,我们需要为要构造的内部类指定父类,如下所示:
jmethodID midInit = (*env)->GetMethodID(env, cls, "<init>", "(Lhelloworld$ExportedFuncs;)V");
Run Code Online (Sandbox Code Playgroud)
另一点是ExportedData该类的构造函数是默认构造函数,它不带任何参数.如果存在参数,则需要将这些参数添加到GetMethodID()函数调用中使用的方法签名中.因此,如果使用了一个构造函数,int那么签名就像"(Lhelloworld$ExportedFuncs;I)V".
| 归档时间: |
|
| 查看次数: |
9240 次 |
| 最近记录: |