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) 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类。