【java】详解native方法的使用

【java】详解native方法的使用目录结构 关于 native 关键字使用 native 关键字使用步骤案例编写 java 文件编译 java 文件获得 h 文件编写 hello cpp 文件部署 hello dll 文件运行 HelloWorld class 文件参考文章 1 关于 native 关键字想必读者已经了解过 native 关键字了 这里笔者就大致囊括一下 被 native 关键字修饰的方法叫做本地方法 本地方法和其它方法不一样 本地方法意味着和平台有关

目录结构:

1,关于native关键字

想必读者已经了解过native关键字了。这里笔者就大致囊括一下,被native关键字修饰的方法叫做本地方法,本地方法和其它方法不一样,本地方法意味着和平台有关,因此使用了native的程序可移植性都不太高。另外native方法在JVM中运行时数据区也和其它方法不一样,它有专门的本地方法栈。native方法主要用于加载文件和动态链接库,由于Java语言无法访问操作系统底层信息(比如:底层硬件设备等),这时候就需要借助C语言来完成了。被native修饰的方法可以被C语言重写。

2,使用native关键字

2.1,使用步骤

  • Java程序中声明native修饰的方法,类似于abstract修饰的方法,只有方法签名,没有方法实现。编译该java文件,会产生一个.class文件。
  • 使用javah编译上一步产生的class文件,会产生一个.h文件。
  • 写一个.cpp文件实现上一步中.h文件中的方法。
  • 将上一步的.cpp文件编译成动态链接库文件.dll。
  • 最后就可以使用System或是Runtime中的loadLibrary()方法加载上一步的产生的动态连接库文件了。

2.2,案例

为了更好理解,该案例的所有都在文件在 D:\JNI\ 目录下。

2.2.1 编写.java文件

【java】详解native方法的使用

复制代码
public class HelloWorld{
    public native void h();//该方法和abstract修饰的方法一样,只有签名。
    
    static{
        System.loadLibrary("hello");//不写文件的后缀,程序会自动加上.dll的。
    }
    
    public static void main(String[] args){
        new HelloWorld().h();//调用
    }
}
复制代码

2.2.2 编译.java文件

在AMD中编译该程序 javac HelloWorld.java ,就会产生一个HelloWorld.class文件。

2.2.3 获得.h文件

将第二步中产生的字节码文件,通过 javah -jni HelloWorld 就会产生一个HelloWorld.h文件。

我们用记事本打开HelloWorld.h文件

复制代码
/* DO NOT EDIT THIS FILE - it is machine generated */ #include  
   
   /* 
    Header for class HelloWorld  
   */ 
    #ifndef _Included_HelloWorld  
   #define _Included_HelloWorld 
    #ifdef __cplusplus  
   extern 
   " 
   C 
   " 
    {  
   #endif 
   /* 
    * Class: HelloWorld * Method: h * Signature: ()V  
   */ 
    JNIEXPORT  
   void 
    JNICALL Java_HelloWorld_h (JNIEnv * 
   , jobject); #ifdef __cplusplus }  
   #endif 
   #endif 
  
复制代码

可以看出,在HelloWorld.java文件中的h()方法已经变成了 JNIEXPORT void JNICALL Java_HelloWorld_h (JNIEnv *, jobject); ,方法名是原来的 包名_类名_方法名 。在该文件中还引用了 jni.h 文件。

2.2.4 编写hello.cpp文件

编写hello.cpp文件的方式有许多,可以利用Visual Studio软件,因为最后需要生成dll文件,因此在下载Visual Studio之前应该查一查版本是否能够生成自己电脑需要的dll版本(32位dll或64为dll)。这里读者下载的是vs2013,该版本既可以生成32的dll,由可以生成64位的dll。关于vs2013生成dll可以参考Visual Studio 2013生成64位dll

因为我们在第一步中调用的文件名称为hello,所以这里的.cpp文件必须为 hello.cpp 文件。这里笔者的文件如下:

复制代码
// hello.cpp : 定义 DLL 应用程序的导出函数。 //  #include "stdafx.h" #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_h(JNIEnv *, jobject) { printf("Hello! ");//打印信息 }
复制代码

可以看出引入了 HelloWorld.h 文件,所以hello.cpp 文件应该和 HelloWorld.h文件在同一个目录下面。如果读者现在编译hello.cpp文件会报错 “jni.h”: No such file or directory 。在 HelloWorld.h 文件中我们引入了 jni.h文件,所以也应该把 jni.h 文件放到同一级目录下面,关于这个文件和相关的文件读者可以到JDK的安装目录下面的include下面查找,更多信息可以查看JDk、JRE、JVM的关系。还应该把 HelloWorld.h 文件中的 #include
 改为 #include jni.h 。最后生成 hello.dll 文件就可以了

2.2.5 部署hello.dll文件

我们使用了 System.loadLibary(hello); 加载动态链接库,这个加载路径是按照java.libary.path进行查询的,读者可以根据System.getProperty(“java.libary.path”)验证,该路径就是环境变量中的path路径。网上有好多说直接把hello.dll仍在 C:\Windows\System32 路径下。不过笔者建议,先应该查看自己环境变量path的值,那么把hello.dll放到path中配置的第一个路径下。

2.2.6 运行HelloWorld.class文件

我们回到  D:/JNI  路径下,使用  java HelloWorld  就成功调用动态连接库了。

【java】详解native方法的使用

笔者的控制台上成功打印了hello!。笔者对这里加载的理解,就是利用反射机制,在运行的时候找到hello.dll文件并且解析,根据动态链接库中的文件名称创建出对象和方法,然后我们就可以利用对象调用方法了。上面的HelloWorld.java文件,创建动态链接库和调用方法都在同一个类中,这样的话一个只需要使用这个类的对象调用方法就可以通过编译和运行了。如果我们引入的是被人的.cpp文件,那么根据.cpp文件中的方法名,在需要的地方做适当调整就可以调用了。

3,使用native关键字目的

为什么要使用Native Method
   java使用起来非常方便,然而有些层次的任务用java实现起来不容易,或者我们对程序的效率很在意时,问题就来了。
   与java环境外交互:
   有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。
   与操作系统交互:
   JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎 样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用C写的,还有,如果我们要使用一些java语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。
    Sun’s Java
    Sun的解释器是用C实现的,这使得它能像一些普通的C一样与外部交互。jre大部分是用java实现的,它也通过一些本地方法与外界交互。例如:类java.lang.Thread 的 setPriority()方法是用java实现的,但是它实现调用的是该类里的本地方法setPriority0()。这个本地方法是用C实现的,并被植入JVM内部,在Windows 95的平台上,这个本地方法最终将调用Win32 SetPriority() API。这是一个本地方法的具体实现由JVM直接提供,更多的情况是本地方法由外部的动态链接库(external dynamic link library)提供,然后被JVM调用。














总的来说,JAVA的native方法适用的情况:
  1、为了使用底层的主机平台的某个特性,而这个特性不能通过JAVA API访问。
  2、为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的。





  3、为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。

4,native关键字特点

   
标识符native可以与所有其它的java标识符连用,但是abstract除外。这是合理的,因为native暗示这些方法是有实现体的,只不过这些实现体是非java的,但是abstract却显然的指明这些方法无实现体。native与其它java标识符连用时,其意义同非Native Method并无差别,比如native static表明这个方法可以在不产生类的实例时直接调用,这非常方便,比如当你想用一个native method去调用一个C的类库时。上面的第三个方法用到了native synchronized,JVM在进入这个方法的实现体之前会执行同步锁机制(就像java的多线程。)
    一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制。这些方法的实现体可以制一个异常并且将其抛出,这一点与java的方法非常相似。当一个native method接收到一些非基本类型时如Object或一个整型数组时,这个方法可以访问这非些基本型的内部,但是这将使这个native方法依赖于你所访问的java类的实现。有一点要牢牢记住:我们可以在一个native method的本地实现中访问所有的java特性,但是这要依赖于你所访问的java特性的实现,而且这样做远远不如在java语言中使用那些特性方便和容易。
    native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节。需要注意当我们将一个本地方法声明为final的情况。用java实现的方法体在被编译时可能会因为内联而产生效率上的提升。但是一个native final方法是否也能获得这样的好处却是值得怀疑的,但是这只是一个代码优化方面的问题,对功能实现没有影响。
    如果一个含有本地方法的类被继承,子类会继承这个本地方法并且可以用java语言重写这个方法(这个似乎看起来有些奇怪),同样的如果一个本地方法被fianl标识,它被继承后不能被重写。
   本地方法非常有用,因为它有效地扩充了jvm.事实上,我们所写的java代码已经用到了本地方法,在sun的java的并发(多线程)的机制实现中,许多与操作系统的接触点都用到了本地方法,这使得java程序能够超越java运行时的界限。有了本地方法,java程序可以做任何应用层次的任务。









版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/226405.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午10:59
下一篇 2026年3月16日 下午10:59


相关推荐

  • 利用PySpark统计相邻字符串对出现的次数

    利用PySpark统计相邻字符串对出现的次数

    2021年11月23日
    67
  • 英语时态=时间+状态

    英语时态=时间+状态十六种时态 时态的 时 指的是动态发生的时间 态 是即动作的状态 英语的句子中都可以找到这两者 时间轴 1 任何动作都会有 3 种状态 一般状态 正在发生 已经完成 2 在某个时点上正在发生的动作是进行时 这个时点可以是过去 现在 将来某个时点 3 在某个时点上已经完成的动作是完成时 这个时点可以是过去 现在 将来某个时点 4 如果动作不是正在进行 又不是已经完成 则用一般时态那么我们如何利用这个时间轴去理解我们 16 种英语时态呢 辨别方法我的理解是这样的 首先你要确定你要表达的东西是基

    2026年3月26日
    2
  • 人工智能正在改变人类地位

    人工智能正在改变人类地位

    2026年3月13日
    3
  • IDEA中MAVEN项目打JAR包的简单方法

    IDEA中MAVEN项目打JAR包的简单方法Idea中为一般的非Web项目打Jar包是有自己的方法的,网上一搜就能查到很多。但是如果是为Maven项目打Jar包,其实是很简单的,因为maven本身就有打Jar包的命令。最简单的方法  首先是在maven项目的pom.xml中添加打包的插件,这里有很多种方式的。最最简单的就是只使用maven-compiler-plugin、maven-jar-plugin插件,并且指定程序入…

    2022年6月19日
    46
  • Xinetd介绍

    Xinetd介绍转自 http blog chinaunix net uid 21411227 id 1826885 html1 什么是 xinetdxinetd 即 extendedinte xinetd 是新一代的网络守护进程服务程序 又叫超级 Internet 服务器 经常用来管理多种轻量级 Internet 服务 xinetd 提供类似于 inetd tcp wrapper 的功能

    2026年3月18日
    2
  • strsep的作用

    strsep的作用在下面这个code中通过strsep将p表示的字符串一“,”分开,例如12,34,56.会先返回12,然后是34,最后是56while((id=strsep(&p,”,”)))我们看看strsep的实现char*strsep(char**s,constchar*ct){   char*sbegin=*s;   char*end;  

    2025年6月26日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号