一、环境准备
Windows7 + WMwareWorkstation9 + RedHatEnterprise5 + jdk1.7.0_51
我的jdk安装路径为 /usr/java/jdk1.7.0_51
二、步骤
1.编写Java代码 Hello.java
package org.bt.hello; public class Hello{ private String name = "bigtree"; /* 无参构造函数 */ public Hello(){ } /* 带参数的构造函数 */ public Hello(String name){ this.name = name; } /* 声明本地函数,返回一个类对象(使用无参构造函数) */ private static native Hello getObjNoParm(); /* 声明本地函数,返回一个类对象(使用带参数的构造函数) */ private static native Hello getObjWithParm(); private void print(){ System.out.println(name + "Hello world!"); } /* 加载共享库 */ static { System.loadLibrary("bigtree"); } public static void main(String []args){ Hello obj = getObjNoParm();/* 调用本地函数,得到一个Hello对象 */ obj.print();/* 使用对象调用函数 */ Hello obj1 = getObjWithParm(); obj1.print(); } }
2.编译Java代码,生成Java字节码文件.class
$ javac -d . Hello.java
3.使用javah生成头文件
$ javah org.bt.hello.Hello
4.编写C函数,包含头文件,实现本地函数 hello.c
#include "org_bt_hello_Hello.h" JNIEXPORT jobject JNICALL Java_org_bt_hello_Hello_getObjNoParm(JNIEnv *env, jclass jcls){ /* 得到类的字节码信息,其中第二个参数为包名+类名 */ jclass helloClass = (*env)->FindClass(env, "org/bt/hello/Hello"); /* 得到构造函数的方法id,第二个参数为类的信息,因为是构造函数,因此第三个参数为<init>,第四个参数为函数签名 */ jmethodID conId = (*env)->GetMethodID(env, helloClass, "<init>", "()V"); /* 调用构造函数,创建对象 */ jobject helloObj = (*env)->NewObject(env, helloClass, conId); return helloObj; } JNIEXPORT jobject JNICALL Java_org_bt_hello_Hello_getObjWithParm(JNIEnv *env, jclass jcls){ /* 得到类的字节码信息 */ jclass helloClass = (*env)->FindClass(env, "org/bt/hello/Hello"); /* 得到构造函数的方法id */ jmethodID conId = (*env)->GetMethodID(env, helloClass, "<init>", "(Ljava/lang/String;)V"); /* 构造参数 */ jstring jname = (*env)->NewStringUTF(env, "zhangsan"); /* 调用构造函数,创建对象 */ jobject helloObj = (*env)->NewObject(env, helloClass, conId, jname); return helloObj; }
5.制作共享库libbigtree.so
$ gcc -fPIC -I /usr/java/jdk1.7.0_51/include -I /usr/java/jdk1.7.0_51/include/linux/ -shared -o libbigtree.so hello.c
6.运行Java程序,测试结果
$ java org/bt/hello/Hello
打印结果为:bigtreeHello world!
zhangsanHello world!
表示jni创建Java类对象成功,并且返回成功。
三、函数签名、类型签名
类型签名
类型 签名 类型 签名
byte | B | byte [] | [B |
short | S | short [] | [S |
int | I | int [] | [I |
long | J | long [] | [J |
float | F | float [] | [F |
double | D | double [] | [D |
char | C | char [] | [C |
boolean | Z | boolean [] | [Z |
java.lang.String | Ljava/lang/String; | String [] | [Ljava/lang/String; |
java.lang.Object | Ljava/lang/Object | object [] | [Ljava/lang/Object; |
org.bt.hello.Hello Lorg/bt/hello/Hello; int [][] [[I
Hello [](对象数组) [Lorg/bt/hello/Hello;
注意:签名是Java层和jni层的对应关系,Java层类型可以自动转换到jni层类型,jni层类型不能自动转换,部分可以自动转换,基本上要手动转换,一般调用函数。
当Java层的类型是引用类型时,对应的jni层的类型为L+包名+类名+分号,切记分号在这里不是分隔符,是类型的一部分。
函数签名
类型 签名
String f() | ()Ljava/lang/String; |
long f(int i, Stu stu) | (ILorg/bt/Stu;)J |
void s(byte [] byte) | ([B)V |
Stu f(Object o, String s, int i) | (Ljava/lang/Object;Ljava/lang/String;I)Lorg/bt/Stu; |
其他类型的函数签名依此类推。。。。