22

我在 C++ 的 GCC 文档中发现了一个有趣的特性:

java_interface

此类型属性通知 C++ 该类是 Java 接口。它只能应用于在外部“Java”块中声明的类。对该接口中声明的方法的调用将使用 GCJ 的接口表机制进行分派,而不是常规的虚拟表分派。

据我了解,它看起来像这样:

extern "Java" {
    class NativeClass __attribute__((java_interface)) {
        //Implementation on native methods goes here.
    }
}

有人知道这方面的细节吗?如何从 Java中调用NativeClass的方法?也许有人在现实生活中尝试过?

4

2 回答 2

6

GCJ 为 Java 提供了两个本地接口:使用 C 的JNI和使用 C++ 的CNI 。由于您引用的示例使用了一个类,因此它必须引用后者。关于接口的CNI 文档仅描述了如何从 C++ 代码访问 Java 中描述的接口。您的示例似乎以相反的方式工作:一个用 C++ 编写的类,可从 Java 访问并用作 Java 接口。

但是关于这个可用的细节很少,所以试验和错误将是试验这个的一种方法,而查看实际的 GCC 源代码将是另一种方法。如果您想查看extern "Java"块和java_interface属性的一个示例,请查看java/lang/Readable.h. 它包含 Java 接口的 C++ 表示java.lang.Readable。正如该文件的第一行所述,它是机器生成的。因此,文档如此少的原因可能是因为您不应该自己编写这些东西。这只是GCJ如何实现CNI的一个细节。更仔细地查看上面的文件,似乎他们甚至违反了他们自己的文档,因为与您引用的片段相比,它Readable.h具有块之外的属性。extern

于 2013-03-06T23:31:54.280 回答
0

我第一次遇到这种块类型不是“java”而是“C”,所以我认为这是同样的兴趣。块定义为:

extern "Java"
{
// some java definition
}

用于向 GCC 指定此块是 java 接口。它用于描述用于定义类的修饰类型。gcc 使用名称 mangling 通过参数等生成函数名称...更多信息在这里:http ://www.agner.org/optimize/calling_conventions.pdf 所以你使用extern "Java"当您使用它导入 java 代码时,您可以像 C/C++ 中的任何函数一样调用它,而无需指定损坏的名称。我对它的唯一用途是用于定义了一些 C 函数的 dll,并在 C++ 代码中加载,因此我使用外部“C”向 GCC 指定此函数的定义不使用名称修饰。好吧,现在如何在 java 中调用本地方法,因为 java 中的一切都是方法,一切都是对象,没有函数。首先,你必须用java描述你的类,你想用本地语言做的所有功能都必须定义为native:private native void print();例如。其次,回到您的本机代码头中,您必须按照命名法定义方法:

extern "Java"
{
        JNIEXPORT YourReturnType JNICALL Java_ClassName_MethodName (JNIEnv* env, jobject obj);
}

至少,所有方法都必须是这样的,因为 JNI 将在方法中发送一个 JNIEnv 指针和一个将是“this”的对象,如果您有其他参数,则必须在 2 个基础之后给出。最后,您只需在本机代码文件中实现所有方法,始终遵循规范,例如:

 JNIEXPORT void JNICALL Jave_Printer_print(JNIEnv* env, jobject obj)
 {
      printf("Hello world");
 }

现在您可以在 Java 中创建一个 Printer 对象并调用定义为 native 的 print 方法。我希望我回答了你的问题。

于 2013-03-04T20:53:16.763 回答