一、环境准备

    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
Bbyte []
[B
shortSshort [][S
intIint [][I
longJlong [][J
floatFfloat [][F
doubleDdouble [][D
charCchar [][C
booleanZboolean [][Z
java.lang.StringLjava/lang/String;String [][Ljava/lang/String;
java.lang.ObjectLjava/lang/Objectobject [][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;

其他类型的函数签名依此类推。。。。