Java泛型和JNI

6pa*_*kid 6 c++ java generics java-native-interface

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

public static native <T, U, V> T foo(U u, V v);
Run Code Online (Sandbox Code Playgroud)

然后把它称为:

//class Foo, class Bar, class Baz are already defined;
Foo f = foo(new Bar(), new Baz());
Run Code Online (Sandbox Code Playgroud)

任何人都可以请我提供一个实际上正在进行此操作的示例或网上的一些教程吗?我问,因为在我的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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我试过修改代码,但现在我得到NoSuchMethodError:

Java代码:

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

use*_*421 9

通常,您应该始终使用javap -s来获取您将要在JNI中查找的方法的签名.不要猜.

  • 但是,当你有一个已经100%正确的工具时,为什么要运行*任何*风险? (5认同)
  • 我不同意.我的本机库有51个函数,我手工编写它们都没有问题.如果你只是停下来思考一下你正在做什么,那真是一点都不困难. (3认同)
  • @JamesMoore 没有什么无关紧要的。您不会做计算机可以为您做得更好、更快、更准确的事情。这实际上是在浪费时间。它引入了很可能发生的主要成本和错误风险,并且具有 100% 有效的缓解策略:不要这样做。 (3认同)
  • `javah`将获取一个类文件并输出一个C头文件,其中包含您需要实现的确切函数 (2认同)
  • 我们在这里讨论的是*Java*方法的签名,从*JNI调用*. (2认同)
  • 没有风险。在这两种情况下,您都需要进行测试以涵盖已构建的内容。测试要么通过,要么没有通过。所产生的手或机器无关紧要。 (2认同)

fal*_*tro 8

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

正如您可能会注意到的那样(并且如您对问题的评论中所述),您无法知道什么类型T.

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

jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()LFoo;");
Run Code Online (Sandbox Code Playgroud)

想想看,你的整个通话序列似乎不合适......你有一个foo原生的,返回的字符串.现在foo寻找getFooBar,返回"富",并返回该呼叫直接的结果,有效地试图返回Foo(Foo getFoo()根据注释),其中串的预期.