【0】README
1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法(JNI)——数值参数与返回值 的基础知识 ;
2) for source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/jni_numParamAndReturnValue
【1】本地方法(JNI)——数值参数与返回值的实现步骤
1)problem+solution:
- 1.1)problem: 在一些平台上 C 语言中的 int 是 16位的,在另外一些平台上是 32 位的;而 java 平台上int 类型总是32位的;
- 1.2) solution: java 本地接口定义了 jint, jlong 等类型;
2) 表 12-1 显示了 java 数据类型和 C 数据类型的对应关系:
- 2.1) 在头文件jni.h 中: 这些类型被 typedef 语句声明为 在 目标平台上等价的类型。 该头文件还定义了常量
JNI_FALSE=0 , JNI_TRUE=1;
3) 用 printf 函数格式化数字
- 3.1)看个荔枝: 以下代码使用本地方法来打印给定域宽度和精度的浮点数:
package com.corejava.chapter12_2;
public class MyPrintf
{
public static native int print(int width, int precision, double value);
}
3.2)注意: 用C实现该方法,所有的int 和 double 参数都要转换为 jint 和 jdouble;
#include "Printf1.h" #include <stdio.h> JNIEXPORT jint JNICALL Java_Printf1_print(JNIEnv* env, jclass cl, jint width, jint precision, jdouble x) { char fmt[30]; jint ret; sprintf(fmt, "%%%d.%df", width, precision); ret = printf(fmt, x); fflush(stdout); return ret; }
4) 用 printf 函数格式化数字的实际实现steps:
- step1) 构建java类,用于定义本地方法; 并构建测试类,用于测试 java 调用本地方法是否成功;
Attention) 若 static 中的 代码改为:
static
{
System.load(“XX”);
}
那么 load 里面的文件应该使用 绝对路径而不是相对路径;(不然会抛出异常, for detailed spec , please visit http://javarevisited.blogspot.jp/2012/03/javalangunsatisfiedlinkerror-no-dll-in.html)
step2)编译MyPrintf, 并用javah 导出类的头文件 .h
javac com/corejava/chapter12_2/MyPrintf.java
javah com.corejava.chapter12_2.MyPrintf
step3) copy com_corejava_chapter12_2_MyPrintf.h 里的 print函数原型到 新建的 MyPrintf.c 文件中, 并实现 print 函数, 如下所示:
#include ""
#include <stdio.h>
JNIEXPORT jint JNICALL Java_com_corejava_chapter12_12_MyPrintf_print
(JNIEnv* env, jclass cl, jint width, jint precision, jdouble x)
{
char fmt[30];
jint ret;
sprintf(fmt, "%%%d.%df", width, precision);
ret = printf(fmt, x);
fflush(stdout);
return ret;
}
step4) 编译该 c文件,并编译到动态装载库中:
gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ MyPrintf.c
gcc -shared -fPIC -o libMyPrintf.so MyPrintf.o
step5)编译并运行java 文件(MyPrintfTest.java)
step5.1)将该加载库 放入到 java.library.path 目录中:
step5.2) 编译java文件并运行
javac com/corejava/chapter12_2/MyPrintfTest.java
java com.corejava.chapter12_2.MyPrintfTest