在Java中使用native

有人可以解释在Java中使用native关键字的原因和原因吗?

根据我的经验,使用本机代码库的缺点很重要:

  • JNI / JNA倾向于破坏JVM的稳定性,特别是如果你试图做一些复杂的事情。 如果您的本机代码错误地使本机代码内存管理失败,那么您可能会崩溃JVM。 如果您的本机代码是不可重入的并且从多个Java线程调用,则会发生不好的事情……偶尔会发生。 等等。

  • 使用本机代码的Java比纯Java或纯C / C ++更难调试。

  • 本机代码可为其他平台无关的Java应用程序引入重要的平台依赖性/问题。

  • 本机代码需要单独的构建框架,并且可能还存在平台/可移植性问题。

一般来说,使用本机代码不会获得太多(如果有的话)额外性能。 虽然您可能认为您的C / C ++比Java更具性能,但JIT编译器在优化这些天方面做得非常好,您必须考虑在JNI边界上进行JNI调用和其他交互的性能成本。

一般来说,你应该将JNI / JNA视为“最后的选择”选项。 如果有任何其他方法可以解决问题,那么这种方式可能更好。

  1. 您可能有一个非Java库,无论出于何种原因,您都必须在Java项目中使用它
  2. 您可能需要集成一些旧的或很少使用的硬件,并且需要实现可能在C / C ++中更容易的接口

如果你想解决本机代码的性能问题,那么99.5%的可能性是错误的方法;-)

有人可以解释在Java中使用native关键字的原因和原因吗?

一旦你看到一个小例子,就会变得清晰:

Main.java

public class Main { public native int intMethod(int i); public static void main(String[] args) { System.loadLibrary("Main"); System.out.println(new Main().intMethod(2)); } } 

Main.c

 #include  #include "Main.h" JNIEXPORT jint JNICALL Java_Main_intMethod( JNIEnv *env, jobject obj, jint i) { return i * i; } 

编译并运行

 javac Main.java javah -jni Main gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \ -I${JAVA_HOME}/include/linux Main.c java -Djava.library.path=. Main 

输出

 4 

使用Oracle JDK 1.8.0_45在Ubuntu 14.04上进行了测试。

所以很明显它允许你:

  • 使用Java中的任意汇编代码调用已编译的动态加载库(此处用C语言编写)
  • 并将结果返回Java

这可以用于:

  • 使用更好的CPU汇编指令(不是CPU便携式)在关键部分编写更快的代码
  • 进行直接系统调用(不是OS便携式)

与低便携性的权衡。

您也可以从C调用Java,但必须首先在C中创建JVM: 如何从C ++调用Java函数?

GitHub上的示例供您玩。

免责声明:这个答案的一部分来自我之前的回答 。 我相信我已经在每个问题上直接回答了OP的问题。

作为Web开发人员,如果您使用Google Web Toolkit,则更有可能遇到native 。 使用该框架,您基本上可以编写Java代码,然后将其编译为可以在浏览器中运行的Javascript。 在GWT中, native关键字用于调用“本机”Javascript代码。

要寻找的术语是JSNI。

  • 性能
  • 与原生环境更紧密地整合
  • 需要使用具有独特function的本机库

示例: JAI (图像处理), Java 3D (OpenGL), JDIC (桌面集成)

Java是独立于平台的,这意味着您用Java编写的程序可以在任何操作系统上运行 – 您甚至不需要重新编译,编译的类文件应该在任何操作系统上运行。

但是,有时您需要在程序中执行某些特定于某个操作系统的操作,并且可能没有纯Java方法来执行您需要执行的操作; 或者您可能需要调用现有的非Java库。 Java平台提供JNI (Java Native Interface)作为调用特定于操作系统的代码的方法。

但是,您应该谨慎使用本机代码,因为它将您的程序绑定到特定的操作系统。

以下是Effective Java 2nd Edition的一些引用,第54项:明智地使用本机方法

从历史上看,本机方法有三个主要用途。 它们提供对特定于平台的工具的访问,例如注册表和文件锁。 他们提供了对遗留代码库的访问,这些代码可以反过来提供对遗留数据的访问。 最后,使用本机方法以本机语言编写性能关键的应用程序部分,以提高性能。

使用本机方法访问特定于平台的工具是合法的,但随着Java平台的成熟,它提供了以前只在主机平台中才能找到的mroe和更多function。 […] 很难建议使用本地方法来提高性能 […]

使用本机方法具有严重的缺点。 由于本机语言不安全 ,使用本机方法的应用程序不再能够免受内存损坏错误的影响。 由于本机语言与平台相关,因此使用本机方法的应用程序的可移植性要低 使用本机代码的应用程序很难进行调试。 进出本机代码存在固定成本,因此如果本机方法只进行少量工作,则可能会降低性能。 最后,本机方法需要“粘合代码”,难以阅读和编写繁琐。

整个项目对问题有更详细的解释。 与整本书一起,强烈推荐。

也可以看看

  • 维基百科/ Java原生界面

GWT的HTML小部件类具有漂亮打印的gem。 当你想检查漂亮的打印机代码时不太有用:(

  /** * All of the markup and content within a given element. */ public final native void setInnerHTML(String html) /*-{ this.innerHTML = html || ''; }-*/;