在 Java 程序中调用 native code;在 native code 中嵌入 Java 虚拟机调用 Java 的代码
注意:
(1) 从Java 环境到 native code 的上下文切换耗时、低效。
(2) JNI 编程,如果操作不当,可能引起 Java 虚拟机的崩溃。
(3) JNI 编程,如果操作不当,可能引起内存泄漏。
c++调用java
返回值 方法名 (参数)
{
JniMethodInfo_ methodInfo;
if (!JniHelper::getStaticMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) {
return;
}
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
说明:
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
说明:JNIEnv *
在Android中,当Java文件被编译成dex文件之后,会由类加载器加载到Dalvik VM(DVM)中,由DVM来进行解释,翻译成机器语言之后,才能由机器来运行。
而对于C/C++来说,其源代码经由Android提供的NDK工具包,可以编译成可执行动态库(即.so文件),之后,Java和C++之间就可以进行通讯了。
那么,在这里,可以想像,Java的Dex字节码和C/C++的so库肯定是同时运行在一个DVM之中,它们是共同使用一个进程空间的,否则,它们怎么彼此沟通呢?
所以在这里,一个关键的中间区域就是Dalvik VM。而对于C/C++,当它们也被加载进DVM之后,由C/C++实现的函数方法等都会被加载 在DVM中的函数表中。
如果想要在C/C++中调 用函数,它们必须要有个东西能够让其访问到这个虚拟机中的函数表。
而这个东西就是JNIEnv *。 对Java虚拟环境的一个引用,在Android中,就是指Dalvik VM;
JniHelper::getStaticMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) java方法为静态
JniHelper::getMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) java方法不为静态
返回值为false表示在相应的java类中没有找到方法
例:JniHelper::getStaticMethodInfo(methodInfo, com/example/text/class1, "function", "()V" -------- C++ 说明:com/example/text为包名、class1为类名 function为方法名 返回值为空参数为空
public static void function() ------------------------------------------------------------------- JAVA
参数 与 java中的参数简写!! 对应关系
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
Object Ljava/lang/String; L用/分割类的完整路径
Array [Ljava/lang/String; [签名 [I
如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:
IIII //4个int型参数的函数
ILjava/lang/String;I //整形,string类型,整形组合 (int x, String a, int y)
返回值 = methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, 参数);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
CallStaticVoidMethod ----- void
CallVoidMethod ------------ void 以函数返回类型的不同,对应不同的函数名
返回值 与 java中的返回值 对应关系
Void void
Object jobject
Boolean jboolean
Byte jbyte
Char jchar
Short jshort
Int jint
Long jlong
Float jfloat
Double jdouble
c++参数 与 java中类型 对应关系
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
Object jobject
Class jclass
String jstring
Object[] jobjectArray
boolean[] jbooleanArray
byte[] jbyteArray
char[] jcharArray
short[] jshortArray
int[] jintArray
long[] jlongArray
float[] jfloatArray
double[] jdoubleArray
例如:
const char* MultiplayerGame::getDeviceName(const char* pBuffer)
{
JniMethodInfo t;
if (!JniHelper::getStaticMethodInfo(t, com/example/text/className, "function", "(Ljava/lang/String;)Ljava/lang/String;")) {
return "error";
}
jstring stringArg1;
if (!pBuffer) {
stringArg1 = methodInfo.env->NewStringUTF("");
} else {
stringArg1 = methodInfo.env->NewStringUTF(pBuffer);
}
jstring text = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, stringArg1);
t.env->DeleteLocalRef(stringArg1);
t.env->DeleteLocalRef(t.classID);
return t.env->GetStringUTFChars(text, 0);
}
实际上我们最常用的参数类型,主要是内建的数据类型、string字符串类型。数据类型可以直接转为j类型,但是string类型需要做如下处理:
jstring jmsg = minfo.env->NewStringUTF(pBuffer); -------------- c++ 中的 const char* 转化为 java 中的 jstring
std::string strValue = JniHelper::jstring2string(text);-------- java 中的 jstring 转化为 c++ 中的 std::string
char* pValue = t.env->GetStringUTFChars(text, 0)--------------- java 中的 jstring 转化为 c++ 中的 char*
释放内存
methodInfo.env->DeleteLocalRef(stringArg1);
java调用c++
c++ 中
extern "C" {
JNIEXPORT 返回值类型 JNICALL
Java_com_example_text_className_方法名(JNIEnv* env, jobject thiz, 参数);
}
JNIEXPORT 返回值类型 JNICALL
Java_com_example_text_className_方法名(JNIEnv* env, jobject thiz, 参数){
return 返回值;
}
java com.example.text 包中的 className 类中
public 返回值类型 方法名 (参数){renturn 返回值}
注意:
(1) 从Java 环境到 native code 的上下文切换耗时、低效。
(2) JNI 编程,如果操作不当,可能引起 Java 虚拟机的崩溃。
(3) JNI 编程,如果操作不当,可能引起内存泄漏。
c++调用java
返回值 方法名 (参数)
{
JniMethodInfo_ methodInfo;
if (!JniHelper::getStaticMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) {
return;
}
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
说明:
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
说明:JNIEnv *
在Android中,当Java文件被编译成dex文件之后,会由类加载器加载到Dalvik VM(DVM)中,由DVM来进行解释,翻译成机器语言之后,才能由机器来运行。
而对于C/C++来说,其源代码经由Android提供的NDK工具包,可以编译成可执行动态库(即.so文件),之后,Java和C++之间就可以进行通讯了。
那么,在这里,可以想像,Java的Dex字节码和C/C++的so库肯定是同时运行在一个DVM之中,它们是共同使用一个进程空间的,否则,它们怎么彼此沟通呢?
所以在这里,一个关键的中间区域就是Dalvik VM。而对于C/C++,当它们也被加载进DVM之后,由C/C++实现的函数方法等都会被加载 在DVM中的函数表中。
如果想要在C/C++中调 用函数,它们必须要有个东西能够让其访问到这个虚拟机中的函数表。
而这个东西就是JNIEnv *。 对Java虚拟环境的一个引用,在Android中,就是指Dalvik VM;
JniHelper::getStaticMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) java方法为静态
JniHelper::getMethodInfo(methodInfo, java中方法所在类的路径, "方法名", "(参数)返回值")) java方法不为静态
返回值为false表示在相应的java类中没有找到方法
例:JniHelper::getStaticMethodInfo(methodInfo, com/example/text/class1, "function", "()V" -------- C++ 说明:com/example/text为包名、class1为类名 function为方法名 返回值为空参数为空
public static void function() ------------------------------------------------------------------- JAVA
参数 与 java中的参数简写!! 对应关系
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
Object Ljava/lang/String; L用/分割类的完整路径
Array [Ljava/lang/String; [签名 [I
如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:
IIII //4个int型参数的函数
ILjava/lang/String;I //整形,string类型,整形组合 (int x, String a, int y)
返回值 = methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, 参数);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
CallStaticVoidMethod ----- void
CallVoidMethod ------------ void 以函数返回类型的不同,对应不同的函数名
返回值 与 java中的返回值 对应关系
Void void
Object jobject
Boolean jboolean
Byte jbyte
Char jchar
Short jshort
Int jint
Long jlong
Float jfloat
Double jdouble
c++参数 与 java中类型 对应关系
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
Object jobject
Class jclass
String jstring
Object[] jobjectArray
boolean[] jbooleanArray
byte[] jbyteArray
char[] jcharArray
short[] jshortArray
int[] jintArray
long[] jlongArray
float[] jfloatArray
double[] jdoubleArray
例如:
const char* MultiplayerGame::getDeviceName(const char* pBuffer)
{
JniMethodInfo t;
if (!JniHelper::getStaticMethodInfo(t, com/example/text/className, "function", "(Ljava/lang/String;)Ljava/lang/String;")) {
return "error";
}
jstring stringArg1;
if (!pBuffer) {
stringArg1 = methodInfo.env->NewStringUTF("");
} else {
stringArg1 = methodInfo.env->NewStringUTF(pBuffer);
}
jstring text = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, stringArg1);
t.env->DeleteLocalRef(stringArg1);
t.env->DeleteLocalRef(t.classID);
return t.env->GetStringUTFChars(text, 0);
}
实际上我们最常用的参数类型,主要是内建的数据类型、string字符串类型。数据类型可以直接转为j类型,但是string类型需要做如下处理:
jstring jmsg = minfo.env->NewStringUTF(pBuffer); -------------- c++ 中的 const char* 转化为 java 中的 jstring
std::string strValue = JniHelper::jstring2string(text);-------- java 中的 jstring 转化为 c++ 中的 std::string
char* pValue = t.env->GetStringUTFChars(text, 0)--------------- java 中的 jstring 转化为 c++ 中的 char*
释放内存
methodInfo.env->DeleteLocalRef(stringArg1);
java调用c++
c++ 中
extern "C" {
JNIEXPORT 返回值类型 JNICALL
Java_com_example_text_className_方法名(JNIEnv* env, jobject thiz, 参数);
}
JNIEXPORT 返回值类型 JNICALL
Java_com_example_text_className_方法名(JNIEnv* env, jobject thiz, 参数){
return 返回值;
}
java com.example.text 包中的 className 类中
public 返回值类型 方法名 (参数){renturn 返回值}