百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

java高级用法之:无所不能的java,本地方法调用实况

haoteby 2025-07-27 20:05 19 浏览

简介

相信每个程序员都有一个成为C++大师的梦想,毕竟C++程序员处于程序员鄙视链的顶端,他可以俯视任何其他语言的程序员。

但事实情况是,无数的程序员从小白到放弃,鉴于C++的难度,最后都投入了java的怀抱。JAVA以他宽广的胸怀接纳了一众无法登顶C++的程序员。

开个玩笑,C和C++的优势在于和系统底层的交互和其运行的速度和效率,JAVA的优势在与广泛的应用框架,可以快速搭建所需的应用程序。两者各有所长。

框架的好处就是降低了程序开发的难度,让应用程序可以快速批量复制。

大家知道,JVM底层是使用C和C++来编写的,而JAVA字节码适合JVM进行交互的,所以直观上看来,JAVA是可以和底层的C++代码进行交互的。那么如何交互呢?会不会很复杂?

今天本文带大家一一揭晓。

JDK的本地方法

所谓本地方法就是调用操作系统或者其他底层库的方法。这些方法属于系统的外部接口,用于程序和操作系统之间进行交互。大家想一下,JDK中有哪些本地的方法呢?

第一个想到的应该就是文件操作,因为文件操作肯定需要依赖与系统底层提供的IO接口。我们先具体来看一下File的delete方法的实现:

    public boolean delete() {
        @SuppressWarnings("removal")
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkDelete(path);
        }
        if (isInvalid()) {
            return false;
        }
        return fs.delete(this);
    }

File的delete方法首先调用SecurityManager来进行权限判断,看是否可以删除。如果可以删除则继续调用FileSystem的delete方法。

我们继续查看FileSystem的delete方法:

public abstract boolean delete(File f);

可以看到FileSystem中的delete方法是一个抽象方法,需要具体的实现。

而这个实现是和平台有关系的,如果你是linux或者mac系统,那么它的实现类是UnixFileSystem,它的delete方法如下:

    public boolean delete(File f) {
        if (useCanonCaches) {
            cache.clear();
        }
        if (useCanonPrefixCache) {
            javaHomePrefixCache.clear();
        }
        return delete0(f);
    }
    private native boolean delete0(File f);

可以看到,delete方法最终会调用delete0方法,而这个方法是一个native方法,表示该方法需要调用系统本地的方法。

JDK提供了一个JAVA调用本地系统方法的实现,叫做JNI,全称是Java Native Interface,它是从JAVA1.1中引入的一项技术。它允许Java代码和其他语言写的代码进行交互。

为了验证JNI的可行性,我们接下来自己实现一个native的方法,并在java中调用,看看是否能够成功。

自定义native方法

在JAVA中定义native方法很简单,我们只需要在方法描述前面加上native关键字即可,这个方法并不需要任何实现。举个具体的例子如下:

public class JNIUsage {

    public native void printMsg();

    public static void main(String[] args) {
        //加载C文件
        System.loadLibrary("JNIUsage");
        JNIUsage jniUsage = new JNIUsage();
        jniUsage.printMsg();
    }
}

上面的例子中,我们定义了一个native的printMsg,然后在main中首先加载包含该实现的Library文件,之后就可以像正常的JAVA方法一样进行调用。

那么这么实现这个native方法呢?

不管熟悉还是不熟悉C++的朋友应该都听过头文件的概念,一般来说我们在头文件中定义好要实现的方法,然后在具体的内容文件中对头文件中定义的方法进行实现。

所以头文件中需要包含这个printMsg的方法,生成头文件可以使用javah命令。

首先进入到JNIUsage源文件的根目录,运行下面的命令:

javah -classpath . -jni com.flydean.JNIUsage

该命令会在项目源代码的根目录中生成一个com_flydean_JNIUsage.h文件。打开看看,具体的内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_flydean_JNIUsage */

#ifndef _Included_com_flydean_JNIUsage
#define _Included_com_flydean_JNIUsage
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_flydean_JNIUsage
 * Method:    printMsg
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_flydean_JNIUsage_printMsg
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

简单点讲,该head文件中定义了一个需要实现的
Java_com_flydean_JNIUsage_printMsg方法。

接下来,我们需要对这个头文件进行实现。

这里我们使用JetBrain公司的Clion开发工具,首先创建一个c++的项目:

注意,这个项目的type需要是shared类型。

然后将com_flydean_JNIUsage.h文件拷贝到项目的根目录下。

这时候是编译不了的,你会发现很多依赖包的错误,我们还需要将JDK home目录中include目录下的jni.h文件,和jni_md.h文件(如果是windows平台该文件在win32目录下,如果是mac平台,该文件在darwin目录下),拷贝到项目的根目录下。

这样编译的错误就不见了。

最后我们修改默认的library.cpp文件,引入com_flydean_JNIUsage.h并实现其中的方法如下所示:

#include "com_flydean_JNIUsage.h"

#include <iostream>

JNIEXPORT void JNICALL Java_com_flydean_JNIUsage_printMsg
        (JNIEnv *, jobject){
    printf("this is www.flydean.com!");
}

目前为止,项目的代码结构应该如下图所示:

接着build–>Build ‘JNIUsage’, 生成libJNIUsage.dylib文件:

====================[ Build | JNIUsage | Debug ]================================
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build /Users/flydean/data/git/cplus/JNIUsage/cmake-build-debug --target JNIUsage
[2/2] Linking CXX shared library libJNIUsage.dylib

Build finished

有了libJNIUsage.dylib,我们还需要将其加入JAVA项目中的path中:

选择java-jni的module,在依赖中选择JARs or Directories, 选择刚刚的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

this is www.flydean.com!

或者你可以在命令行中将libJNIUsage.dylib加入到java运行的classpath中即可。

总结

以上就是一个简单的使用JAVA调用native方法的例子。大家可以看到,步骤还是挺复杂的,那么有没有其他更加简单的方法,让JAVA来调用native方法呢?有的,这就是JNA,我们会在后续的文章中深入进行介绍。

本文的代码可以参考
https://github.com/ddean2009/learn-java-base-9-to-20.git

本文已收录于
http://www.flydean.com/01-jni-overview/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

相关推荐

一日一技:用Python程序将十进制转换为二进制

用Python程序将十进制转换为二进制通过将数字连续除以2并以相反顺序打印其余部分,将十进制数转换为二进制。在下面的程序中,我们将学习使用递归函数将十进制数转换为二进制数,代码如下:...

十进制转化成二进制你会吗?#数学思维

六年级奥赛起跑线:抽屉原理揭秘。同学们好,我是你们的奥耀老师。今天一起来学习奥赛起跑线第三讲二进制计数法。例一:把十进制五十三化成二进制数是多少?首先十进制就是满十进一,二进制就是满二进一。二进制每个...

二进制、十进制、八进制和十六进制,它们之间是如何转换的?

在学习进制时总会遇到多种进制转换的时候,学会它们之间的转换方法也是必须的,这里分享一下几种进制之间转换的方法,也分享两个好用的转换工具,使用它们能够大幅度的提升你的办公和学习效率,感兴趣的小伙伴记得点...

c语言-2进制转10进制_c语言 二进制转十进制

#include<stdio.h>intmain(){charch;inta=0;...

二进制、八进制、十进制和十六进制数制转换

一、数制1、什么是数制数制是计数进位的简称。也就是由低位向高位进位计数的方法。2、常用数制计算机中常用的数制有二进制、八进制、十进制和十六进制。...

二进制、十进制、八进制、十六进制间的相互转换函数

二进制、十进制、八进制、十六进制间的相互转换函数1、输入任意一个十进制的整数,将其分别转换为二进制、八进制、十六进制。2、程序代码如下:#include<iostream>usingna...

二进制、八进制、十进制和十六进制等常用数制及其相互转换

从大学开始系统的接触计算机专业,到现在已经过去十几年了,今天整理一下基础的进制转换,希望给还在上高中的表妹一个入门的引导,早日熟悉这个行业。一、二进制、八进制、十进制和十六进制是如何定义的?二进制是B...

二进制如何转换成十进制?_二进制如何转换成十进制例子图解

随着社会的发展,电器维修由继电器时代逐渐被PLC,变频器,触摸屏等工控时代所替代,特别是plc编程,其数据逻辑往往涉及到数制二进制,那么二进制到底是什么呢?它和十进制又有什么区别和联系呢?下面和朋友们...

二进制与十进制的相互转换_二进制和十进制之间转换

很多同学在刚开始接触计算机语言的时候,都会了解计算机的世界里面大多都是二进制来表达现实世界的任何事物的。当然现实世界的事务有很多很多,就拿最简单的数字,我们经常看到的数字大多都是十进制的形式,例如:我...

十进制如何转换为二进制,二进制如何转换为十进制

用十进制除以2,除的断的,商用0表示;除不断的,商用1表示余0时结束假如十进制用X表示,用十进制除以2,即x/2除以2后为整数的(除的断的),商用0表示;除以2除不断的,商用1表示除完后的商0或1...

十进制数如何转换为二进制数_十进制数如何转换为二进制数举例说明

我们经常听到十进制数和二进制数,电脑中也经常使用二进制数来进行计算,但是很多人却不清楚十进制数和二进制数是怎样进行转换的,下面就来看看,十进制数转换为二进制数的方法。正整数转二进制...

二进制转化为十进制,你会做吗?一起来试试吧

今天孩子问把二进制表示的110101改写成十进制数怎么做呀?,“二进制”简单来说就是“满二进一”,只用0和1共两个数字表示,同理我们平常接触到的“十进制”是“满十进一”,只用0-9共十个数字表示。如果...

Mac终于能正常打游戏了!苹果正逐渐淘汰Rosetta转译

Mac玩家苦转译久矣!WWDC2025苹果正式宣判Rosetta死刑,原生游戏时代终于杀到。Metal4光追和AI插帧技术直接掀桌,连Steam都连夜扛着ARM架构投诚了。看到《赛博朋克2077》...

怎么把视频的声音提出来转为音频?音频提取,11款工具实测搞定

想把视频里的声音单独保存为音频文件(MP3/AAC/WAV/FLAC)用于配音、播客、听课或二次剪辑?本文挑出10款常用工具,给出实测可复现的操作步骤、优缺点和场景推荐。1)转换猫mp3转换器(操作门...

6个mp4格式转换器测评:转换速度与质量并存!

MP4视频格式具有兼容性强、视频画质高清、文件体积较小、支持多种编码等特点,适用于网络媒体传播。如果大家想要将非MP4格式的视频转换成MP4的视频格式的话,可以使用MP4格式转换器更换格式。本文分别从...