尽管这种情况极少发生,你也许希望调用不是用Java语言写的子程序。通常,这样的子程序是CPU的或是你所工作环境的执行代码——也就是说,本机代码。例如,你希望调用本机代码子程序来获得较快的执行时间。

或者,你希望用一个专用的第三方的库,例如统计学包。然而,因为Java程序被编译为字节码,字节码由Java运行时系统解释(或动态编译),看起来在Java程序中调用本机代码子程序是不可能的。幸运的是,这个结论是错误的。

Java提供了native关键字,该关键字用来声明本机代码方法。一旦声明,这些方法可以在Java程序中被调用,就像调用其他Java方法一样。

为声明一个本机方法,在该方法之前用native修饰符,但是不要定义任何方法体。例如:

public native int meth() ;

声明本机方法后,必须编写本机方法并要执行一系列复杂的步骤使它与Java代码链接。

很多本机方法是用C写的。把C代码结合到Java 程序中的机制是调用Java Native Interface (JNI)。该方法学由Java 1.1创建并在Java 2中增强。(Java 1.0是用不同的方法,该方法已经过时),关于JNI的详尽描述超出了本书的范围。但是下面的描述为多数应用程序提供了足够的信息。

理解该过程的最简单的方法是完成一个例子。开始,输入下面的短程序,该程序使用了一个名为test( )的native方法。

// A simple example that uses a native method.
public class NativeDemo { int i; public static void main(String args[]) { NativeDemo ob = new NativeDemo(); ob.i = 10; System.out.println("This is ob.i before the native method:" + ob.i); ob.test(); // call a native method System.out.println("This is ob.i after the native method:" + ob.i); } // declare native method public native void test() ; // load DLL that contains static method static { System.loadLibrary("NativeDemo"); }
}

注意test( )方法声明为native且不含方法体。简而言之这是我们用C语言实现的方法。同时注意static块。像本书前面解释过的,一个static块仅在程序开始执行时执行(更为简单的说,当它的类被加载时执行)。这种情况下,它用来加载包含本地执行方法test( )的动态链接库(你不久就会看到怎样创建这个库)。

该库由loadLibrary( )方法加载。loadLibrary( )方法是System类的组成单元。它的一般形式为:

static void loadLibrary(String filename)

这里,filename是指定保存该库文件名的字符串。在Windows环境下,该文件的扩展名为.DLL。

写完程序后,编译它生成NativeDemo.class。然后,你必须用javah.exe生成一个文件:NativeDemo.h(javah.exe包含在JDK中)。在执行test( )时你要包含NativeDemo.h。
为生成NativeDemo.h,用下面的命令:

javah -jni NativeDemo

该命令生成名为NativeDemo.h的头文件。该文件必须包含在实现test()的C文件中。该命令的输出结果如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class NativeDemo */
#ifndef _Included_NativeDemo
#define _Included_NativeDemo
#ifdef _ _cplusplus
extern "C" {
#endif
/* * Class: NativeDemo * Method: test * Signature: ()V */
JNIEXPORT void JNICALL Java_NativeDemo_test (JNIEnv *, jobject);
#ifdef _ _cplusplus
}
#endif
#endif

请特别注意下面一行,该行定义了所要创建的test( )函数的原型:

JNIEXPORT void JNICALL Java_NativeDemo_test(JNIEnv *, jobject);

注意函数的名称是Java_NativeDemo_test( )。调用本机函数你必须用这样的名字。也就是说,不是生成一个名为test( )的C函数,而是创建一个名为Java_NativeDemo_test( )函数。

加入前缀NativeDemo是因为它把test( )方法作为NativeDemo类的一部分。

记住,其他类可以定义它们自己的与NativeDemo定义的完全不同的本地test( )方法。前缀中包括类名的方法解决了区分不同版本的问题。作为一个常规方法,给本机函数取名,前缀中必须包括声明它们的类名。

生成了必备的头文件后,可以编写test( )执行文件并把它存在一个名为NativeDemo.c的文件中:

/* This file contains the C version of the test() method.
*/
#include <jni.h>
#include "NativeDemo.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_NativeDemo_test(JNIEnv *env, jobject obj)
{ jclass cls; jfieldID fid; jint i; printf("Starting the native method.\n"); cls = (*env)->GetObjectClass(env, obj); fid = (*env)->GetFieldID(env, cls, "i", "I"); if(fid == 0) { printf("Could not get field id.\n"); return; } i = (*env)->GetIntField(env, obj, fid); printf("i = %d\n", i); (*env)->SetIntField(env, obj, fid, 2*i); printf("Ending the native method.\n");
}

注意此文件包含具有接口信息的jni.h文件。该文件由你的Java 编译器提供。头文件NativeDemo.h预先已由javah创建。

该函数中,GetObjectClass( )方法用来获得一个含有NativeDemo类信息的C结构。GetFieldID( )方法返回一个包含该类域名“i”信息的C结构。GetIntField()检索该域原来的值。SetIntField( )存储该域的一个更新值(别的处理其他数据类型的方法参看文件jni.h)。

生成NativeDemo.c文件后,必须编译它生成一个DLL文件。用微软C/C++编译器来做,使用下面的命令行:

Cl /LD NativeDemo.c

它生成了一个名为NativeDemo.dll的文件。该步骤完成,你可以执行Java 程序。该程序输出如下:

This is ob.i before the native method: 10
Starting the native method.
i = 10
Ending the native method.
This is ob.i after the native method: 20

使用native的特殊环境是依赖于实现和环境的。而且,与JAVA代码接口的指定方式必须改变。你必须仔细考虑完成你Java开发系统文件的本机方法。

Java基础篇之什么是本机方法相关推荐

  1. Java基础篇:加入带自变量的方法

    大多数方法不需要自变量.自变量对方法没有特殊要求.也就是说,带自变量的方法,可以完成各种数据操作,它还可以用在很多有微妙差别的情况.为了说明这一点,让我们举一个非常简单的例子.下面的方法返回数字10的 ...

  2. Java基础篇:对象拷贝:clone方法 以及 序列化

    我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...

  3. Java 基础篇(一)基本概念

    Java 基础篇系列文章目录 Java 基础篇(一)基本概念 Java 基础篇(二)数据类型 Java 基础篇(三)控制逻辑 文章目录 Java 基础篇系列文章目录 Java(软件开发) Java(编 ...

  4. 你所需要的java基础篇深入解析大汇总

    java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...

  5. Java基础篇4——数组

    Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...

  6. Java基础篇3——流程控制

    Java基础篇3--流程控制 1.顺序结构 正常代码的流程即是顺序流程 2.分支结构 2.1.if-else分支 if(条件表达式) {语句块1; } if(条件表达式) {语句块1; } else ...

  7. Java基础篇2——运算符

    Java基础篇2--运算符 1.运算符 1.1.算数运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取余运算符 1.2.关系运算符 所有以关系运算符作为最终运算的 ...

  8. Java基础篇1——变量与数据类型

    Java基础篇1--变量与数据类型 1.标识符命名规则 标识符以由大小写字母.数字.下划线(_)和美元符号($)组成,但是不能以数字开头. 大小写敏感 不能与Java语言的关键字重名 不能和Java类 ...

  9. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

最新文章

  1. pytorch——torch.backends.cudnn.benchmark = True
  2. mysql5.5更改端口后初始化_centos7 修改mysql5.7默认端口后启动异常
  3. c语言中文件读写面试题,在C ++中有效读取非常大的文本文件
  4. 【抽象代数】因子分解与域的扩展
  5. es6 作为属性名的 Symbol
  6. 解决Oracle的http://localhost:1158/em页面打不开的问题
  7. fiddler修改客户端发出去的请求
  8. php 执行任务,php多进程执行任务的说明
  9. SAP MM 顾问在实施项目工作中的苦逼和优势
  10. 保险行业的自动化场景
  11. LiveData原理解析
  12. SOA对话:金融风暴不会阻碍SOA市场发展
  13. Android 系统截屏实现
  14. 未来属于智能,智能存在未在每个角落-称重
  15. C#获取文件的Content-Type(MIME Type)的三种方法
  16. ax.patches 表示什么?
  17. (转载)持续集成(第二版)[来自:Martin Fowler]
  18. Ubuntu 16.04下NVIDIA GTX 960M显卡驱动的安装
  19. 【51单片机】定时器/计数器的工作原理和结构(一)
  20. 1901怀化学院KHJ错题集

热门文章

  1. [转载] 利用Python构建股票交易策略 !
  2. linux 2.6 内核的移植
  3. elasticsearch-head的使用
  4. 1.PHP与Web页面的交互
  5. Java + selenium 元素定位(3)之By TagName
  6. javascript 函数与对象
  7. Python学习笔记总结
  8. 软件开发知识--[ADO.NET Entity Framework]
  9. Adaptive Feature Recombination and Recalibration for Semantic Segmentation: Application to Brain Tum
  10. 【ROS学习笔记】(四)订阅者Subscriber的实现