为什么有些Java库方法委托给具有几乎相同签名的本机方法?

时间:2016-08-15 01:10:59

标签: java native

在深入研究JRE库的源代码之后,我注意到一个奇怪的常见代码结构,如下所示:

public int foo(double bar) {
    return foo0(bar);
}

private native int foo0(double bar);

此代码模式的目的是什么,为什么使用它而不是简单地将底层本机方法公开为公共方法?

2 个答案:

答案 0 :(得分:47)

原生版本只是一个实现细节。

此模式将方法的公共接口与实际实现分开。

我至少看到了5个有用的原因:

  • 测试目的(你可以模拟java方法调用)
  • 替代实现:特定版本的java库可以在纯java形式中实现该方法,而无需调用本机实现(在swing代码中常见)。
  • 向后兼容性:如果在新版本中,该方法接受一些额外的参数,则可以保留原始的java方法签名并调整本机实现。
  • 输入/输出验证:大多数情况下,在调用本机版本之前,java代码会对输入参数进行一些检查,并在需要时抛出异常。
  • 隔离:直接使用本机代码的方法数量有限,允许对内部代码结构进行更多更改。

您可能会发现更多优势。

答案 1 :(得分:14)

private native int foo(double bar);

因此,最终必须为其实现调用C ++函数。特别是,它最终会调用一个名称类似的函数:

Java_MyClass_foo

如果有多个具有不同签名的原生foo方法,会发生什么?并发症。如果这样做,Java会将类型信息添加到它查找的方法的名称中。但是如果你坚持使用非重载方法就会更容易。

public int foo(double bar) {
    return foo0(bar);
}

private native int foo0(double bar);

foo0已被赋予唯一名称,永远不应该有理由添加另一个foo0。这使得C ++的实现变得简单,它永远不必处理受损的名称。即使foo最终获得了重载,它也会调用foo1而不是foo0,并且C ++ JNI实现将不必处理重载的额外复杂问题。