【问题标题】:Java generics and JNIJava 泛型和 JNI
【发布时间】:2010-02-09 10:22:30
【问题描述】:

是否可以使用带有通用参数的 JNI 调用本机 CPP 函数?类似于以下内容:

public static native <T, U, V> T foo(U u, V v);

然后这样称呼它:

//class Foo, class Bar, class Baz are already defined;
Foo f = foo(new Bar(), new Baz());

谁能给我一个实际执行此操作的示例或网络上执行此操作的一些教程?我问是因为在我的 CPP JNI 函数(由 JVM 调用)中,我得到了不满意的链接错误。

CPP 代码如下:

JNIEXPORT jobject JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2)
{
    jclass bar_class = env->FindClass("Bar");
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/Object;");
//getFoo() is defined as `public Foo getFoo();` in Bar.java
    return env->CallObjectMethod(obj1, getFooMethod);
}

编辑:

我已经尝试通过修改代码,但现在我得到 NoSuchMethodError:

Java 代码:

public static native <U, V> String foo(U u, V v);
//...
String str = foo(new Bar(), new Baz());

CPP 代码:

JNIEXPORT jstring JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2)
{
    jclass bar_class = env->FindClass("Bar");
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/String;");
    //getFoo() is now defined as `public String getFoo();` in Bar.java
    return env->CallObjectMethod(obj1, getFooMethod);
}

这是否意味着 JNI 不支持泛型或者我遗漏了什么?

【问题讨论】:

  • JNI 没有做任何神奇的事情。与 bog 标准 Java 代码一样,您将从哪里创建 T

标签: java c++ generics java-native-interface


【解决方案1】:

一般来说,您应该始终使用 javap -s 来获取您将在 JNI 中寻找的方法的签名。不要猜。

【讨论】:

  • 我不同意。我的本机库有 51 个函数,我对它们都进行了手工编码,没有任何问题。如果你停下来想一想你在做什么,让它们变得正确并不难。
  • 但是,当您拥有一个已经 100% 正确的工具时,为什么还要冒任何风险呢?
  • javah 将获取一个类文件并输出一个包含您需要实现的确切功能的 C 头文件
  • 我们这里讨论的是Java方法的签名,被称为from JNI。
  • @JamesMoore 没有什么不相关的。你不会做计算机可以为你做的更好、更快、更准确的事情。这实际上是在浪费时间。它引入了高发生概率的主要成本和错误风险,并且具有 100% 有效的缓解策略:不要这样做。
【解决方案2】:

有很多关于堆栈溢出类型擦除的问题(例如Get generic type of java.util.List),您想要做的事情对于 JNI 和 Java 本身都是不可能的。 foo 的运行时类型签名是(在两个世界中,或者实际上只有一个世界)Object foo(Object u, Object v),它将在返回值上执行一个隐式类强制转换为您调用它的任何类型。

您可能会注意到(正如您对问题的评论中提到的),您无法知道 T 是什么类型。

编辑
顺便说一句,getFoo 方法应该返回 'Foo',所以你不应该这样做

jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()LFoo;");

想一想,你的整个调用序列似乎不合适......你有一个 foo 这是本机的,返回字符串。现在fooBar 中查找getFoo,它返回'Foo',并直接返回该调用的结果,有效地尝试返回一个Foo(根据评论Foo getFoo()),其中需要字符串.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多