C/C++调用Java代码(属性和方法)
back>>
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)booleanjboolean unsigned char 8, unsignedbyte jbytesigned char 8char jchar unsigned short 16, unsignedshortjshortshort 16intjint long 32long jlong __int64 64float jfloatfloat 32double jdoubledouble 64void 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");//取得jmethodIDjmethodID id_func = env->GetMethodID(clazz_TestNative,"methodTest","");sign用于指定取得的属性/方法的类型如果sign指定为(I)V,则取回void methodTest(int)的methodID如果sign指定为(D)V,则取回void methodTest(double)的methodID*/
??? 签名sign
?
用来表示要取得的属性/方法的类型类型 相应的签名boolean Zbyte Bchar Cshort Sint Ilong Lfloat Fdouble Dvoid Vobject 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.TestNativeCompiled from "TestNative.java"public class video1.TestNative extends java.lang.Object{public java.lang.String name; Signature: Ljava/lang/String;public video1.TestNative(); Signature: ()Vpublic int signTest(int, java.util.Date, int[]); Signature: (ILjava/util/Date;[I)Ipublic native void sayHello(); Signature: ()Vpublic 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);//得到jfieldIDjfieldID fieldID_prop = env->GetFieldID(native_clazz,"name","Ljava/lang/String;");jfieldID fieldID_num = env->GetFieldID(native_clazz,"number","I");//得到jmethodIDjmethodID 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类。
?
?