1. JNIEnv对象
对于本地函数
- JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){
- cout<<"Hello Native Test !"<<endl;
- }
JNIEnv类型代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。
JNIEnv的指针会被JNI传送到本地方法的实现函数中来对Java端的代码进行操作
JNIEnv类中的函数:
NewObject/NewString/New<TYPE>Array
Get/Set<TYPE>Field
Get/SetStatic<TYPE>Field
Call<TYPE>Method/CallStatic<TYPE>Method
2. Java数据类型与C/C++数据类型的对应关系
- Java类型 别名 本地类型 字节(bit)
- boolean jboolean unsigned char 8, unsigned
- byte jbyte signed char 8
- char jchar unsigned short 16, unsigned
- short jshort short 16
- int jint long 32
- long jlong __int64 64
- float jfloat float 32
- double jdouble double 64
- void void n/a
- Object _jobject *jobject
3. 获取jclass
为了能够在C/C++使用Java类,jni.h头文件中专门定义了jclass类型来表示Java中的Class类
jclass的取得:
JNIEnv类中有如下几个简单的函数可以取得jclass
jclass FindClass(const char* clsName)
jclass GetObjectClass(jobject obj)
jclass GetSuperClass(jclass obj)
FindClass 会在classpath系统环境变量下寻找类,需要传入完整的类名,注意包与包之间是用"/"而不是"."来分割
如:jclass cls_string= env->FindClass("java/lang/String");
4. 本地代码访问Java类中的属性与方法
JNI在jni.h头文件中定义了jfieldID,jmethodID类表示Java端的属性和方法
在访问或设置Java属性的时候,首先就要现在本地代码中取得代表Java属性的jfieldID,然后才能在本地代码中进行Java属性操作。
同样,在需要调用Java端的方法时,也需要取得代表方法的jmethodID才能进行Java方法调用
JNIEnv获取相应的fieldID和jmethodID的方法:
GetFieldID/GetMethodID
GetStaticFieldID/GetStaticMethodID
GetMethodID也可以取得构造函数的jmethodID。创建Java对象时调用指定的构造函数。
如:env->GetMethodID(data_Clazz,"<int>","()V")
5. sign签名
对于 jfieldID GetFieldID(jclass clazz, const char *name, const char *sign)
clazz代表该属性所在的类,name表示方法名称,sign是签名
例如TestNative类中有两个重载方法:
- package video1;
- public class TestNative{
- public void methodTest(int i){
- System.out.println(i);
- }
- public void methodTest(double d){
- System.out.println(d);
- }
- }
- /*
- 在C/C++代码中调用其中一个methodTest方法:
- 首先取得要调用方法所在的类
- jclass clazz_TestNative = env->FindClass("video1/TestNative");
- //取得jmethodID
- jmethodID id_func = env->GetMethodID(clazz_TestNative,"methodTest","");
- sign用于指定取得的属性/方法的类型
- 如果sign指定为(I)V,则取回void methodTest(int)的methodID
- 如果sign指定为(D)V,则取回void methodTest(double)的methodID
- */
签名sign
- 用来表示要取得的属性/方法的类型
- 类型 相应的签名
- boolean Z
- byte B
- char C
- short S
- int I
- long L
- float F
- double D
- void V
- object L用/分隔包的完整类名: Ljava/lang/String;
- Array [签名 [I [Ljava/lang/Object;
- Method (参数1类型签名 参数2类型签名···)返回值类型签名
使用javap命令来产生签名
javap -s -p [full class Name]
-s 表示输出签名信息
-p 同-private,输出包括private访问权限的成员信息
例子:
- C:\E\java\workspaces\myeclipseblue\JNITest\bin>javap -s -private video1.TestNative
- Compiled from "TestNative.java"
- public class video1.TestNative extends java.lang.Object{
- public java.lang.String name;
- Signature: Ljava/lang/String;
- public video1.TestNative();
- Signature: ()V
- public int signTest(int, java.util.Date, int[]);
- Signature: (ILjava/util/Date;[I)I
- public native void sayHello();
- Signature: ()V
- public static void main(java.lang.String[]);
- Signature: ([Ljava/lang/String;)V
- }
6. 本地方法调用Java方法的完整示例:
- TestNative.java
- package video1;
- import java.util.Date;
- public class TestNative {
- public String name="Test";
- public int number =100;
- public int signTest(int i,Date date,int[] arr){
- System.out.println("Sign Test");
- return 0;
- }
- //native关键字修饰的方法,其内容是C/C++编写的,java中不必为它编写具体的实现
- public native void sayHello();
- public static void main(String[] args) {
- System.loadLibrary("NativeCode");
- TestNative tn = new TestNative();
- tn.sayHello();
- }
- }
- C/C++代码
- #include "video1_TestNative.h"
- #include <iostream>
- using namespace std;
- JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){
- cout<<"Hello Native Test !"<<endl;
- //因为test不是静态函数,所以传进来的就是调用这个函数的对象
- //否则就传入一个jclass对象表示native()方法所在的类
- jclass native_clazz = env->GetObjectClass(obj);
- //得到jfieldID
- jfieldID fieldID_prop = env->GetFieldID(native_clazz,"name","Ljava/lang/String;");
- jfieldID fieldID_num = env->GetFieldID(native_clazz,"number","I");
- //得到jmethodID
- jmethodID methodID_func=env->GetMethodID(native_clazz,"signTest","(ILjava/util/Date;[I)I");
- //调用signTest方法
- env->CallIntMethod(obj,methodID_func,1L,NULL,NULL);
- //得到name属性
- jobject name = env->GetObjectField(obj,fieldID_name);
- //得到number属性
- jint number= env->GetIntField(obj,fieldID_num);
- cout<<number<<endl;//100
- //修改number属性的值
- env->SetIntField(obj,fieldID_num,18880L);
- number= env->GetIntField(obj,fieldID_num);
- cout<<number<<endl;//18880
- }
图解签名:
- 编译source.cpp,执行TestNative.java类。
转载于:http://zzqrj.iteye.com/blog/1285262