使用 JNI 创建、填充和返回 Java 类实例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10130819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use JNI to Create, Populate and Return a Java Class Instance
提问by c12
I'm trying to use a JNI function to create a Java class and set some properties of that class using the DeviceId.java constructor method. I'm able to get the constructor method using the GetMethodID, but how would I create a new instance of Device.java and then set the properties (setId and setCache). The goal is to return a fully populated instance of Device.java Object to the caller. Any ideas?
我正在尝试使用 JNI 函数创建一个 Java 类并使用 DeviceId.java 构造函数方法设置该类的一些属性。我可以使用 GetMethodID 获取构造函数方法,但是如何创建 Device.java 的新实例,然后设置属性(setId 和 setCache)。目标是向调用者返回一个完全填充的 Device.java 对象实例。有任何想法吗?
JNI Function:
JNI 函数:
JNIEXPORT jobject JNICALL Java_com_test_getID(JNIEnv *env, jclass cls)
{
jmethodID cnstrctr;
jclass c = (*env)->FindClass(env, "com/test/DeviceId");
if (c == 0) {
printf("Find Class Failed.\n");
}else{
printf("Found class.\n");
}
cnstrctr = (*env)->GetMethodID(env, c, "<init>", "(Ljava/lang/String;[B)V");
if (cnstrctr == 0) {
printf("Find method Failed.\n");
}else {
printf("Found method.\n");
}
return (*env)->NewObject(env, c, cnstrctr);
}
Java Class:
Java类:
package com.test;
public class DeviceId {
private String id;
private byte[] cache;
public DeviceId(){}
public DeviceId(String id, byte[] cache){
this.id=id;
this.cache=cache;
}
public byte[] getCache() {
return cache;
}
public void setCache(byte[] cache) {
this.cache = cache;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
采纳答案by Edward Thomson
When you called GetMethodID
, you provided the signature for the two-arg constructor. Thus, you just need to pass your jstring
and a jbytearray
when you call NewObject
- for example:
当您调用 时GetMethodID
,您提供了双参数构造函数的签名。因此,您只需要在调用时传递您的jstring
和 a - 例如:jbytearray
NewObject
return (*env)->NewObject(env, c, cnstrctr, id, cache);
You don't need to call the setId
and setCache
methods unless you decide to call the 0-arg constructor - and that just complicates your code since you'll have to call GetMethodID
for those and call them. Simpler to continue down the route you're on.
除非您决定调用 0-arg 构造函数,否则您不需要调用setId
和setCache
方法 - 这只会使您的代码复杂化,因为您必须GetMethodID
调用它们并调用它们。更简单地继续沿着你所走的路线。
回答by kosiara - Bartosz Kosarzycki
I wanted to return a customJava object from JNI's cpp codeback to Java. The solution is to return a jobject
from cpp function and use our custom Java object in native method declaration.
我想将JNI 的 cpp 代码中的自定义Java 对象返回给 Java。解决方案是从 cpp 函数返回一个并在本地方法声明中使用我们自定义的 Java 对象。jobject
public class PyError {
public String message;
public boolean occurred;
public PyError(boolean occurred, String message){
this.message = message;
this.occurred = occurred;
}
}
and method declaration in Java:
和 Java 中的方法声明:
native PyError nativePythonErrorOccurred();
on the cpp side:
在 cpp 方面:
extern "C" JNIEXPORT jobject JNICALL
Java_com_your_package_nativePythonErrorOccurred(JNIEnv *env, jobject obj) {
jclass javaLocalClass = env->FindClass("com/your/package/PyError");
if (javaLocalClass == NULL) {
LOGP("Find Class Failed.\n");
} else {
LOGP("Found class.\n");
}
jclass javaGlobalClass = reinterpret_cast<jclass>(env->NewGlobalRef(javaLocalClass));
// info: last argument is Java method signature
jmethodID javaConstructor = env->GetMethodID(javaGlobalClass, "<init>", "(ZLjava/lang/String;)V");
if (javaConstructor == NULL) {
LOGP("Find method Failed.\n");
} else {
LOGP("Found method.\n");
}
jobject pyErrorObject = env->NewObject(javaGlobalClass, javaConstructor, true, env->NewStringUTF("Sample error body"));
return pyErrorObject;
}
Determine the signature of the method using
javap -s java.your.package.YourClass
.
Also, have a look here.
使用 确定方法的签名
javap -s java.your.package.YourClass
。另外,看看这里。
If you encounter error similar to: JNI ERROR (app bug): attempt to use stale Global 0xf2ac01ba
your method signature is wrong, you're passing wrong arguments to env->NewObject()
or you're not using global state of jni objects - more here.
如果您遇到类似于以下JNI ERROR (app bug): attempt to use stale Global 0xf2ac01ba
的错误:您的方法签名错误,您将错误的参数传递给env->NewObject()
或您没有使用 jni 对象的全局状态 - 更多信息请点击此处。