当前位置: 首页 > 后端技术 > Java

java进阶用法:无所不能的java,现场调用本地方法

时间:2023-04-01 16:37:27 Java

简介相信每个程序员都有一个成为C++高手的梦想。毕竟C++程序员处于程序员鄙视链的顶端,他可以看不起任何其他语言的程序员。但事实是,无数程序员因无知而放弃,鉴于C++的难度,最终投向了java的怀抱。JAVA以其博大的胸怀接纳了一批C++无法登顶的程序员。开个玩笑,C和C++的优势在于与系统底层的交互以及运行的速度和效率。JAVA的优势在于其广泛的应用程序框架,可以快速构建所需的应用程序。两者各有所长。该框架的好处是降低了程序开发的难度,可以快速批量复制应用。众所周知,JVM底层是用C和C++编写的,而JAVA字节码适合JVM交互,所以直观上,JAVA可以与底层C++代码进行交互。那么如何互动呢?会不会很复杂?今天这篇文章就带大家一一揭晓。JDK的native方法所谓native方法就是调用操作系统或者其他底层库的方法。这些方法属于系统的对外接口,用于程序与操作系统的交互。想一想,JDK中的本地方法有哪些?首先想到的应该是文件操作,因为文件操作肯定需要依赖系统底层提供的IO接口。我们看一下File的delete方法的实现:publicbooleandelete(){@SuppressWarnings("removal")SecurityManagersecurity=System.getSecurityManager();如果(安全!=null){security.checkDelete(路径);}if(isInvalid()){返回false;}返回fs.delete(this);}File的delete方法先调用SecurityManager判断权限看是否可以删除。如果可以删除,继续调用FileSystem的delete方法。我们继续看FileSystem的delete方法:publicabstractbooleandelete(Filef);可以看出FileSystem中的delete方法是一个抽象方法,需要具体实现。而这个实现是和平台相关的。如果你是linux或者mac系统,那么它的实现类是UnixFileSystem,它的delete方法如下:publicbooleandelete(Filef){if(useCanonCaches){cache.clear();}if(useCanonPrefixCache){javaHomePrefixCache.clear();}返回delete0(f);}privatenativebooleandelete0(Filef);可以看到,delete方法最终会调用delete0方法,而这个方法是native方法,说明该方法需要调用系统本地方法。JDK提供了一种JAVA调用本地系统方法的实现,称为JNI,全称JavaNativeInterface,是从JAVA1.1引入的技术。它允许Java代码与用其他语言编写的代码进行交互。为了验证JNI的可行性,我们接下来实现一个native方法,在java中调用,看能否成功。自定义native方法在JAVA中定义native方法非常简单,只需要在方法描述前加上native关键字即可,这个方法不需要任何实现。具体例子如下:publicclassJNIUsage{publicnativevoidprintMsg();publicstaticvoidmain(String[]args){//加载C文件System.loadLibrary("JNIUsage");JNIUsagejniUsage=newJNIUsage();jniUsage.printMsg();}}在上面的例子中,我们定义了一个原生的printMsg,然后在main中先加载包含实现的Library文件,然后像普通的JAVA方法一样调用它。那么如何实现这个native方法呢?熟悉或不熟悉C++的朋友应该都听说过头文件的概念。一般来说,我们在头文件中定义要实现的方法,然后在具体的内容文件中实现头文件中定义的方法。因此头文件中需要包含printMsg方法,可以使用javah命令生成头文件。首先进入JNIUsage源文件的根目录,运行如下命令:javah-classpath。-jnicom.flydean.JNIUsage该命令会在项目源码的根目录下生成一个com_flydean_JNIUsage.h文件。打开看看,具体内容如下:/*DONOTEDITTHISFILE-itismachinegenerated*/#include/*Headerforclasscom_flydean_JNIUsage*/#ifndef_Included_com_flydean_JNIUsage#define_Included_com_flydean_JNIUextage#ifdef"erncplus"plus{#endif/**Class:com_flydean_JNIUsage*Method:printMsg*Signature:()V*/JNIEXPORTvoidJNICALLJava_com_flydean_JNIUsage_printMsg(JNIEnv*,jobject);#ifdef__cplusplus}#endif#endif简单来说,head文件定义了一个需要实现的Java_com_flydean_JNIUsage_printMsg方法。接下来,我们需要实现这个头文件。这里我们使用JetBrain的Clion开发工具,首先创建一个c++工程:注意这个工程的类型需要共享。然后将com_flydean_JNIUsage.h文件复制到项目根目录下。这时候编译不了,你会发现依赖包有很多错误。我们还需要在JDK主目录的include目录下添加jni.h文件,以及jni_md.h文件(如果是windows平台,该文件在win32目录下,如果是mac平台,则文件在darwin目录下),复制到工程根目录下。这样,编译错误就会消失。最后,我们修改默认的library.cpp文件,导入com_flydean_JNIUsage.h,实现方法如下:www.flydean.com!");}至此,项目的代码结构应该如下图所示::50%"/>然后build-->Build'JNIUsage',生成libJNIUsage.dylib文件:======================[Build|JNI用法|调试]==================================/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake--build/Users/flydean/data/git/cplus/JNIUsage/cmake-build-debug--targetJNIUsage[2/2]LinkingCXXsharedlibrarylibJNIUsage.dylibBuildfinished有了libJNIUsage.dylib,我们还需要添加到JAVA工程中在路径中:选择java-jni模块,选择JARs或者Directoriesindependencies,选择刚才的libJNIUsage.dylib目录保存后,即可运行JAVA代码,结果如下:/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home/bin/java-Djava.library.path=/Users/flydean/data/git/cplus/JNIUsage/cmake-build-debug-Dfile.encoding=UTF-8-classpath/Users/flydean/data/git/learn-java-base-9-to-20/java-jni/target/classes:com.flydean.JNIUsage这是www.flydean.com!或者你可以将libJNIUsage.dylib添加到命令行运行的java的类路径中。总结以上是一个使用JAVA调用native方法的简单例子。可以看到,步骤比较复杂,那么有没有其他更简单的方法让JAVA调用native方法呢?没错,这就是JNA,我们会在后续的文章中深入介绍。本文代码可参考https://github.com/ddean2009/learn-java-base-9-to-20.git本文已收录于http://www.flydean.com/01-jni-概述/最通俗的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!