在Java中使用native

vai*_*hav 7 java native

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

Cir*_*四事件 7

有人可以解释在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));
    }
}
Run Code Online (Sandbox Code Playgroud)

Main.c:

#include <jni.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_intMethod(
    JNIEnv *env, jobject obj, jint i) {
  return i * i;
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

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

输出:

4
Run Code Online (Sandbox Code Playgroud)

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

所以很明显它允许你:

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

这可以用于:

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

与低便携性的权衡.

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

GitHub上的示例供您玩.

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


And*_*s_D 6

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

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


Ste*_*n C 2

根据我的经验,使用本机代码库的缺点是显着的:

  • JNI / JNA 往往会破坏 JVM 的稳定性,特别是当您尝试执行复杂的操作时。如果您的本机代码出现本机代码内存管理错误,则可能会导致 JVM 崩溃。如果您的本机代码是不可重入的并且从多个 Java 线程调用,那么糟糕的事情将会发生……偶尔发生。等等。

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

  • 本机代码可能会给独立于平台的 Java 应用程序引入重要的平台依赖性/问题。

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

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

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