• 自己实现一个Native方法的调用


    JNI

    开始本篇的内容之前,首先要讲一下JNI。Java很好,使用的人很多、应用极 广,但是Java不是完美的。Java的不足体现在运行速度要比传统的C++慢上许多之外,还有Java无法直接访问到操作系统底层如硬件系统,为此 Java提供了JNI来实现对于底层的访问。JNI,Java Native Interface,它是Java的SDK一部分,JNI允许Java代码使用以其他语言编写的代码和代码库,本地程序中的函数也可以调用Java层的函 数,即JNI实现了Java和本地代码间的双向交互。

    Native

    JDK开放给用户的源码中随处可见Native方法,被Native关键字声明的方法说明该方法不是以Java语言实现的,而是以本地语言实现的,Java可以直接拿来用。这里有一个概念,就是本地语言,本地语言这四个字,个人理解应该就是可以和操作系统直接交互的语言。

    通过JNI调用C++写的代码

    下面演示一下如何写一段简单的C++代码,在Java中用一个Native方法去调用的步骤。C++代码使用到的IDE是Microsoft Visual Studio 2010,这是一款市面上开发C++代码最常用的IDE,功能强大。OK,接下来一步一步演示一下:

    1、写一段Java代码。由于我们在Windows环境下,所以用的是一 个.dll文件,如果在Linux环境下的话,用的是一个.so文件。最后C++代码写完之后要生成一个.dll/.so文件,生成的文件可以使用 static静态加载的方法加载进来,也可以通过配置环境变量的方式,这里选择前者。

    复制代码
     1 public class TestMain
     2 {
     3     static
     4     {
     5         System.load("D:" + File.separator + "Hello.dll");
     6     }
     7     
     8     public native static void Hello();
     9     
    10     public static void main(String[] args)
    11     {
    12         Hello();
    13     }
    14 }
    复制代码

    2、cmd进入命令行程序中,进入刚才写的那个类的CLASSPATH下,CLASSPATH就是.class文件所在的根路径。运行“JNI -jni com.xrq.test1.TestMain” ,表示为指定的类下的Native方法生成.h文件。.h文件是C/C++使用的头文件,用于将声明和实现分离,不熟悉C/C++的同学也不用深究

    3、进入自己的CLASSPATH底下查看一下有没有多一个.h文件,我自己这边的是

    这个命名是javah这个命令的实现帮我们命名的,只要多了这个文件就可以了

    4、打开VS2010,文件-->新建-->项目,命名为“Hello”,和我们静态块中load进去的名字要一致

    注意选择DLL

    5、刚才通过javah生成的.h文件复制到Hello目录下

    6、把这个.h添加到项目中,右键头文件-->添加-->现有项,选择Hello目录下的“com_xrq_test1_TestMain.h”添加进去就好了

    7、右键 源文件-->添加-->新建项,选择.cpp文件,随便命名,我叫做source.cpp。实现很简单,就打印一下“Hello”这个字符 串。cout是C++的控制台输出语句,相当于Java的System.out.print(),endl是换行的意思,所以这整句相当于Java的 System.out.println("Hello");

    8、修改“com_xrq_test1_TestMain.h”头文件中的#include <jni.h>为#include "jni.h"

    9、把%JAVA_HOME%/include目录下的“jni.h”%JAVA_HOME%/include/win32目录下的“jni_md.h”两 个文件复制到Hello目录下,用刚才添加“com_xrq_test1_TestMain.h”一样的方式添加这两个.h文件到头文件目录中,这样目录 下Hello目录下应该多出了两个文件,VS2010工程目录下应该有3个.h文件。JAVA_HOME就是JDK安装目录,不知道的cmd进入命令行,echo %JAVA_HOME%就可以查看了。这一步很重要,没有这一步,C++程序是无法运行的

    10、右键项目-->生成,就可以生成.dll文件了

    11、刚才生成的.dll文件是32系统下的,32系统的用户可以直接使用这 个.dll文件了,只要复制到静态代码块指定的目录下就好了。换句话说,64位系统的用户是不能使用这个.dll文件的。如果要生成64位计算机可以使用 的.dll文件,还要额外再为64位计算机成生一个.dll文件

    下拉菜单里面没有x64的点击下拉菜单-->配置管理器配置一下,自己摸索一下就好了,VS2010有自带x64的

    12、生成64位的.dll,复制到D盘下即可,也就是静态代码块里面指定的Hello.dll的路径


    13、运行一下第一步里面写的Java程序,C++打印的“Hello”就出来了,至此,Java通过JNI调用C++编写的代码的功能完成。

    有什么心得?

    自己完成了这么一个过程,肯定是颇有成就感的,成就感过后,我们可以从这13个步骤中感悟到什么?至少个人有以下心得:

    1、1个类中有很多Native方法-->这个类中的所有Native方法生成到1个.h文件中-->本地代码生成一个.dll/.so文件和一个类的Native方法实现相对应

    2、为什么有Native方法的类中必有这么一段代码

    1 private static native void ();
    2 static {
    3         registerNatives();
    4     }

    现在想来,估计和我们的静态代码块起的作用一样,都是为这个类导入特定的.dll/.so文件用的。至于为什么不能像我们这么写,个人猜测,是因为不同的用户磁盘上的.dll/.so文件位置不固定,和JDK安装目录相关?

    3、Java不在乎Native方法是用什么语言实现的,只要一来语言能和底层打 交道就好了,二来语言实现完可以提供出来.dll/.so文件。因此同一个Native方法,如果不同的Java虚拟机去调用它,那么结果可能都不同,比 如Object的hashCode(),当然,运行效率也不尽然相同,因为不同的虚拟机对于不同的Native方法有自己的实现。

  • 相关阅读:
    评七种武器之碧玉刀
    EFCore join table and AutoMapper
    虚拟网络的简单知识总结
    kubernetes中不可见的OOM
    神通数据库安装配置方法
    OpenEuler2203安装Redislabs的简单记录
    Redislabs的简单使用与benchmark测试结果
    springMVC捕获404错误并统一返回json格式 规格严格
    zeromq简介及各个通讯模式实例详解(附java实现) 规格严格
    记录java.lang.NoClassDefFoundError: org/springframework/boot/logging/DeferredLogFactory错误 规格严格
  • 原文地址:https://www.cnblogs.com/szlbm/p/5504603.html
Copyright © 2020-2023  润新知