Java基础篇之什么是本机方法
尽管这种情况极少发生,你也许希望调用不是用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基础篇之什么是本机方法相关推荐
- Java基础篇:加入带自变量的方法
大多数方法不需要自变量.自变量对方法没有特殊要求.也就是说,带自变量的方法,可以完成各种数据操作,它还可以用在很多有微妙差别的情况.为了说明这一点,让我们举一个非常简单的例子.下面的方法返回数字10的 ...
- Java基础篇:对象拷贝:clone方法 以及 序列化
我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...
- Java 基础篇(一)基本概念
Java 基础篇系列文章目录 Java 基础篇(一)基本概念 Java 基础篇(二)数据类型 Java 基础篇(三)控制逻辑 文章目录 Java 基础篇系列文章目录 Java(软件开发) Java(编 ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- Java基础篇4——数组
Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...
- Java基础篇3——流程控制
Java基础篇3--流程控制 1.顺序结构 正常代码的流程即是顺序流程 2.分支结构 2.1.if-else分支 if(条件表达式) {语句块1; } if(条件表达式) {语句块1; } else ...
- Java基础篇2——运算符
Java基础篇2--运算符 1.运算符 1.1.算数运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取余运算符 1.2.关系运算符 所有以关系运算符作为最终运算的 ...
- Java基础篇1——变量与数据类型
Java基础篇1--变量与数据类型 1.标识符命名规则 标识符以由大小写字母.数字.下划线(_)和美元符号($)组成,但是不能以数字开头. 大小写敏感 不能与Java语言的关键字重名 不能和Java类 ...
- 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)
菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...
最新文章
- pytorch——torch.backends.cudnn.benchmark = True
- mysql5.5更改端口后初始化_centos7 修改mysql5.7默认端口后启动异常
- c语言中文件读写面试题,在C ++中有效读取非常大的文本文件
- 【抽象代数】因子分解与域的扩展
- es6 作为属性名的 Symbol
- 解决Oracle的http://localhost:1158/em页面打不开的问题
- fiddler修改客户端发出去的请求
- php 执行任务,php多进程执行任务的说明
- SAP MM 顾问在实施项目工作中的苦逼和优势
- 保险行业的自动化场景
- LiveData原理解析
- SOA对话:金融风暴不会阻碍SOA市场发展
- Android 系统截屏实现
- 未来属于智能,智能存在未在每个角落-称重
- C#获取文件的Content-Type(MIME Type)的三种方法
- ax.patches 表示什么?
- (转载)持续集成(第二版)[来自:Martin Fowler]
- Ubuntu 16.04下NVIDIA GTX 960M显卡驱动的安装
- 【51单片机】定时器/计数器的工作原理和结构(一)
- 1901怀化学院KHJ错题集
热门文章
- [转载] 利用Python构建股票交易策略 !
- linux 2.6 内核的移植
- elasticsearch-head的使用
- 1.PHP与Web页面的交互
- Java + selenium 元素定位(3)之By TagName
- javascript 函数与对象
- Python学习笔记总结
- 软件开发知识--[ADO.NET Entity Framework]
- Adaptive Feature Recombination and Recalibration for Semantic Segmentation: Application to Brain Tum
- 【ROS学习笔记】(四)订阅者Subscriber的实现