在JAVA核心库中经常看到native方法,题主浅显知道JAVA有JNI这个机制。
问题1:但是为什么在JAVA核心库中没有看到JNI的loadLibrary而是直接用native修饰下方法。而我们自己实现JNI需要loadLibrary这个函数去加载so或者dll。为什么JAVA核心库当中不需要loadLibrary呢?
问题2:如果是JAVA核心库中有使用loadLibrary(如果由于我没找到的话),那问题就变成,loadLibrary的实现不也应该是C去实现的吗?这就变成了鸡生蛋生鸡的问题。
问题3:如何修改JAVA核心库中的native方法中的C语言的实现的整个过程?
题主初探JAVA,希望回答的尽可能详细。感谢。
1、在 Java 的核心库中,你看不到 JNI 的 loadLibrary 方法,是因为这些 native 方法在 Java 应用程序初始化时已经被加载并连接到 Java 虚拟机了。这是因为 Java 的核心库是由 C 和 C++ 编写的,并且在初始化 Java 虚拟机时已经被加载。
2、如果你看到了 Java 核心库中使用了 loadLibrary 方法,那么这个方法是由 Java 代码实现的,而不是由 C 或 C++ 代码实现的。
3、修改 Java 核心库中的 native 方法的 C 语言实现的整个过程非常复杂。首先,你需要下载源代码,然后修改 C 或 C++ 代码,然后重新编译和链接库文件。最后,你还需要将修改后的库文件安装到系统中,并在你的 Java 应用程序中加载新的库文件。这是一个非常复杂的过程,需要有深入的 C 和 C++ 知识,以及了解 Java 的 JNI 机制。
您可以参考以下资料学习 Java 的 JNI 机制:
1、Java JNI 编程指南:http://www.cnblogs.com/dolphin0520/p/3877280.html
2、JNI 入门指南:https://www.cnblogs.com/dolphin0520/p/3920407.html
这些资料可以帮助您了解 Java 的 JNI 机制,并学习如何在 Java 中调用本地代码。
在Java中,有一个特殊的类叫做System
,它位于java.lang
包中。这个类有一个静态方法loadLibrary
,可以用来加载本地库(也就是以.so
为后缀的文件,在Windows中是.dll
)。例如,你可以这样调用它:
System.loadLibrary("mylibrary");
Java核心库(也就是包含在Java运行时环境(JRE)中的类)是在Java虚拟机(JVM)加载时自动加载的,所以你不需要手动调用loadLibrary
来加载这些类。
在Java核心库中使用的是本地方法而不是JNI方法。
本地方法是在Java语言中定义的方法,而JNI方法则是在其他语言(例如C或C++)中定义的方法。本地方法的实现是通过在Java代码中使用native
修饰符来声明的,然后在本地库(例如.so
文件)中实现。与此相比,JNI方法的实现则是在其他语言中实现的,然后使用JNI接口调用。
在Java核心库中为什么使用的是本地方法而不是JNI方法呢?这是因为本地方法的性能更高,因为它们直接调用本地库,而不需要经过JNI接口。另外,本地方法的使用方式也比较简单,只需要使用native
修饰符声明方法即可,而不需要写额外的JNI代码。
如果你想修改Java核心库中的本地方法的C语言实现,你需要进行以下步骤:
src/java.base
目录中。javac
)将修改后的源代码编译成字节码。.so
文件)。jar
)将修改后的字节码和本地库打包成Java核心库(例如rt.jar
)。注意,这是一个比较复杂的过程,需要涉及到多种不同的语言和工具。如果你不熟悉C语言和Java的编译和打包过程,可能会遇到一些困难。
另外,需要注意的是,修改Java核心库的本地方法的C语言实现可能会导致兼容性问题。因此,在修改之前应该充分考虑可能的后果,并做好相应的测试工作。
3、如果想修改 Java 核心库中的 native 方法的 C 实现,需要:
找到 Java 核心库的源代码
修改相应的 C 源文件
编译修改后的 C 代码
将修改后的本地代码库链接到 Java 核心库中
重新编译 Java 核心库
这个过程可能需要编写 Makefile 或者其他脚本来自动化。
仅供参考,望采纳,谢谢。
1.在 Java 核心库中没有看到 JNI 的 loadLibrary 是因为 JNI 在底层实现中已经被加载了。Java 核心库中的 native 方法只是在定义时使用了 native 修饰符,它们已经被预先编译成本地代码,并且在 JVM 启动时已经被加载。
2.loadLibrary 函数也是由 C 语言实现的,但是它并不是在 Java 代码中调用,而是在 JVM 启动时自动调用的。它是 JVM 的一部分,负责加载和链接本地代码库,如果 JVM 没有加载 JNI 库,Java 中的 native 方法就无法执行。所以题目中的第二个问题可以理解成蛋生鸡而非鸡生蛋
3.要修改 Java 核心库中的 native 方法的 C 语言实现,需要重新编译 Java 核心库。这需要对 Java 源码进行修改并重新编译,并将编译后的二进制文件替换原来的 Java 核心库。
如果是本地库(so,dll)需要被修改,那么需要重新编译并且将编译出来的新库替换掉旧的库。
这个过程需要非常熟练的 C/C++ 编程知识以及足够的经验,而且也非常复杂。
当然,你可以在自己的项目中使用 JNI 来调用本地代码。这样你可以编写自己的本地代码来扩展 Java 的功能,或者使用第三方库。 使用 JNI 的过程需要编写 Java 代码和本地代码,并且需要使用 javah 工具生成 JNI 头文件,还需要用到 System.loadLibrary() 或者Runtime.getRuntime().loadLibrary()来加载库
总而言之,虽然修改 Java 核心库的 native 方法的 C 语言实现是可行的,但是这需要具备相当丰富的编程知识和经验,并且也是一个非常复杂的过程,通常更好的方法是使用 JNI 调用自己编写的本地代码来扩展 Java 程序的功能.
我如下给你演示一下,请参考:
1、新建Operation.java文件
public class Operation {
public native int add(int a, int b);
}
2、使用javah生成.h头文件
javah -jni Operation
生成的Operation.h文件内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Operation */
#ifndef _Included_Operation
#define _Included_Operation
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Operation
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_Operation_add
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
3、编写add方法的声明实现文件:dllmain.cpp
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "jni.h"
#include <stdio.h>
#include "Operation.h"
JNIEXPORT jint JNICALL Java_Operation_add(JNIEnv* env, jobject obj, jint a, jint b) {
printf("%s", "call c++ native method!!");
return a + b;
}
int main(){
return 0;
}
4、编译成动态链接库(dll文件)
在windows上面编译cpp文件,需要先安装编译器,可以使用mingw或者visual studio,此处使用mingw,注意:因为java安装的是64位,MinGW也必须使用64位,否则会报Can’t load IA 32-bit .dll on a AMD 64-bit platform的错误。
MinGW如何安装可以参考:https://blog.csdn.net/qq_29212901/article/details/109303983
gcc -I/c/jdk1.8.0_212/include -I/c/jdk1.8.0_212/include/win32 -Wl,--add-stdcall-alias -shared -o dllmain.dll dllmain.cpp
参数:-Wl,–add-stdcall-alias 可以为函数加上标准调用前缀(stdcall @nn)。
这样编译出的dll就可以了。都知道win32中dll中的函数要求有标准调用前缀,在JNI中不方便手动处理这个,Sun又没说清楚这事由编译器办。所以搞得我很郁闷。找了大半个月,终于在一个很古老的网页上找到答案。
5、写一个测试代码调用上面编写的native add方法 NativeDemo.java
public class NativeDemo {
static {
System.loadLibrary("dllmain");
}
public static void main(String[] args) {
System.out.println(new Operation().add(1, 3));
}
}
6、运行结果如下:
问题1:JAVA核心库中经常使用 native 修饰方法来表示这个方法是本地方法,在JVM运行时会调用本地库中对应的函数来实现这个方法。在Java核心库中,通常是在JVM启动时由JVM自动调用 System.loadLibrary() 方法来加载本地库,所以在Java核心库代码中不需要显式调用 System.loadLibrary() 方法。
对于我们自己实现JNI, 通常是我们自己编写Java代码,在Java代码中显式调用 System.loadLibrary() 方法来加载本地库。
简单说就是JAVA核心库加载库文件是在JVM启动时由JVM内部自动调用实现的,而我们自己实现JNI需要在代码中显式调用 loadLibrary() 方法来加载本地库
问题2:loadLibrary 方法的实现可能是由JNI实现的,JNI的实现也是由C语言实现的。 JNI 的实现包含了加载本地库的功能,而这些功能在JVM的实现中已经被调用并执行了。
所以从某种意义上来说可以说是由 JNI 实现的,但 JNI 又是由 C 语言编写的,而 JNI 的实现在JVM内部,所以在java核心库中不需要在代码中调用loadLibrary()。
对于这个问题可以说是一种套娃问题, JVM 本身也是由 C 语言实现的, JNI 的实现也在 JVM 内部实现
问题3:要修改Java核心库中的 native 方法中的 C 语言的实现,需要遵循以下步骤:
首先你需要获得Java核心库的源代码。这可能需要从官网下载或从开源项目中获取。
定位到需要修改的 native 方法。核心库中的 native 方法通常位于 .c 或 .cpp 文件中,需要找到对应的文件并打开进行修改。
修改C代码实现。修改之后进行编译,生成新的本地库
替换原来的本地库。将新的本地库替换到JAVA的安装目录下,或者在运行时通过 -D java.library.path参数指定新的本地库。
需要注意的是,这是一个非常复杂的过程,需要对Java核心库和C/C++代码有深入的了解和专业知识。修改核心库代码也可能导致其他问题,如果不当修改可能会导致程序崩溃或数据错误。因此,在修改之前应该进行充分的测试和评估。
1.2.native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
3.用法:1.编写带有native声明的方法的Java类(java文件)
2.使用javac命令编译编写的Java类(class文件)
3.使用javah -jni ****来生成后缀名为.h的头文件(.h的文件)
4.使用其他语言(C、C++)实现本地方法
5.将本地方法编写的文件生成动态链接库(dll文件)