我试图通过JNI将每个引用从c ++传递到java。首先,我尝试了一些简单的代码:
爪哇
public static void inc(int val) {
System.out.println("inc called: " + val);
val++;
}
public static void dec(int val) {
System.out.println("dec called: " + val);
val--;
}
这应该简单地使用Java方法输入/减少用c ++代码创建的变量。 c ++部分看起来像这样:
C ++
jmethodID jDec = env->GetStaticMethodID(cls, "dec", "(I)V");
jmethodID jInc = env->GetStaticMethodID(cls, "inc", "(I)V");
jint val = 10;
printf("%d\n", val);
env->CallStaticVoidMethod(cls, jDec, &val);
printf("%d\n", val);
env->CallStaticVoidMethod(cls, jInc, val);
printf("%d\n", val);
如您所见,我按照参考和每个值尝试了两种方法。
输出
10
dec called: -401031272
10
inc called: 10
10
在c ++代码中,值始终为10,在Java中,它是地址或值。
如果你能给我一个提示,那就太好了,非常感谢你。
答案 0 :(得分:4)
正如Wojtek所说,Java通过价值传递论据。您可以添加返回值 Java代码:
public static int inc2(int val) {
System.out.println("inc called: " + val);
return val + 1;
}
然后从C ++中调用它:
jmethodID inc2 = env->GetStaticMethodID(cls, "inc2", "(I)I");
jint result = env->CallStaticIntMethod(cls, inc2, val);
printf("inc2: %d\n", result);
另一种方法是使用包装类:
public class IntWrapper {
private int value;
public IntWrapper(int value) {
setInt(value);
}
public int getInt() {
return value;
}
public void setInt(int value) {
this.value = value;
}
}
以及以下Java方法:
public static void inc3(IntWrapper val) {
val.setInt(val.getInt()+1);
}
然后,您可以从C ++代码中调用它:
// create wrapper object
jclass wrapper = env->FindClass("IntWrapper");
jmethodID constructor = env->GetMethodID(wrapper, "<init>", "(I)V");
jobject wrapperObject = env->NewObject(wrapper, constructor, val);
// print value before increment
jmethodID getInt = env->GetMethodID(wrapper, "getInt", "()I");
jint ret = env->CallIntMethod(wrapperObject, getInt);
printf("Wrapper value: %d\n", ret);
// call inc3
jmethodID inc3 = env->GetStaticMethodID(cls, "inc3", "(LIntWrapper;)V");
env->CallStaticVoidMethod(cls, inc3, wrapperObject);
// print result
ret = env->CallIntMethod(wrapperObject, getInt);
printf("Wrapper value after increment: %d\n", ret);
或者你可以使用int []而不是Wojtek建议的包装类。
答案 1 :(得分:1)
&#34;这应该简单地使用Java方法在c ++代码中创建一个变量。&#34;不,它不应该。 Java按值传递参数,因此您不是递增和递减C ++变量,而是函数val
和inc
中的变量dec
本地。
答案 2 :(得分:0)
首先,即使在纯C ++上下文中,以下内容也没有意义:
jint val = 10;
// ...
env->CallStaticVoidMethod(cls, jDec, &val);
&val
返回局部变量val
的地址。这通常甚至不能用C ++编译。亲自尝试一下:
int x = 10;
int y = &x; // error
它在这里编译的原因是CallStaticVoidMethod
是一个可变函数。声明如下:
void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
最后的...
部分意味着&#34;任何事情都会发生,但如果您在运行时传递了我无法正确处理的任何内容,则您有责任。&#34;
所以这种做法显然是注定的。
然而,实际问题是 Java在C ++意义上没有引用。一切都是通过价值传递的;没有相当于C ++ int &
参数。
然而,Java有指针,即使它主要是调用它们,令人困惑,&#34;引用&#34;。例如,Java Integer
引用在C ++中将是Integer *
(假设在C ++中存在Integer
类)。天真地,你可以改变你的方法&#39;签名来获取Integer
个参数并摆弄C ++方面的对象,但这也不会起作用,因为Java的Integer
类是不可变的,所以你不能增加它。
那你真的能做什么?
您可以利用 1元素数组,但这不是一个非常好的解决方案;它增加了你必须做的错误检查的数量。为了使代码足够健壮,您必须确保数组不包含0或&gt; 1个元素。此外,数组会让看到代码的每个人都感到困惑。
另一种解决方案是创建自己的可变整数类并使用该类。像这样:
public class MutableInteger {
private int value;
public MutableInteger(int value) {
this.value = value;
}
public void increment() {
++value;
}
public void decrement() {
--value;
}
public String toString() {
return String.valueOf(value);
}
public int get() {
return value;
}
// other operations
}
(...)
public static void inc(MutableInteger val) {
System.out.println("inc called: " + val);
val.increment();
}
由于它,代码的C ++方面会更复杂。您必须首先找到您的类,查找并调用其构造函数,查找并调用increment
方法,然后最终找到并调用get
方法。理想情况下,您将所有这些包装在一个小的C ++函数中:
void increment(JNIEnv *env, int &value)
{
jclass javaClass = env->FindClass(env, "your/package/MutableInteger");
jmethodID constructor = env->GetMethodID(env, javaClass, "<init>", "(I)V");
jobject javaObject = env->NewObject(env, javaClass, constructor, value);
jmethodID incrementMethod = env->GetMethodID(env, javaClass, "increment", "()V");
env->CallVoidMethod(javaObject, incrementMethod, value);
jmethodID getMethod = env->GetMethodID(env, javaClass, "get", "()I");
value = env->CallIntMethod(javaObject, getMethod);
}
(我已经把它写在了我的头顶,所以它可能包含错误,你当然应该在实际代码中添加许多错误处理和可能的一些jmethodID
优化。)< / p>
这值得吗?可能不是。如果从许多其他Java代码调用Java方法并且您希望保持一致的接口,那么这可能是合理的。如果仅从C ++代码调用Java方法,则整个方法都是无意义的,然后正确的解决方案是将方法更改为返回递增的值:
public static int inc(int val) {
System.out.println("inc called: " + val);
return val + 1;
}