NativeUtil类定义如下
public class NativeUtil {
static {
System.loadLibrary("native-lib");
}
public static int ADD = 0;
public static int SUB = 1;
public static int MULTI = 2;
public static int DIVISION = 3;
public static native int calculate(int arg0,int arg1,int symbol);
}
其中,ADD,SUB,MULTI,DIVISION,分别表示加减乘除,C中取出arg0和arg1的值,根据symbol和NativeUtil的静态成员变量对比,判断进行哪种操作,然后返回计算结果。
要解决第一个问题,我们得先了解C与Java数据类型的转换,转换表如下:
Java 类型 | 本地类型 | 描述 |
boolean | jboolean | C/C++8位整型 |
byte | jbyte | C/C++带符号的8位整型 |
char | jchar | C/C++无符号的16位整型 |
short | jshort | C/C++带符号的16位整型 |
int | jint | C/C++带符号的32位整型 |
long | jlong | C/C++带符号的64位整型e |
float | jfloat | C/C++32位浮点型 |
double | jdouble | C/C++64位浮点型 |
Object | jobject | 任何Java对象,或者没有对应java类型的对象 |
Class | jclass | Class对象 |
String | jstring | 字符串对象 |
Object[] | jobjectArray | 任何对象的数组 |
boolean[] | jbooleanArray | 布尔型数组 |
byte[] | jbyteArray | 比特型数组 |
char[] | jcharArray | 字符型数组 |
short[] | jshortArray | 短整型数组 |
int[] | jintArray | 整型数组 |
long[] | jlongArray | 长整型数组 |
float[] | jfloatArray | 浮点型数组 |
double[] | jdoubleArray | 双浮点型数组 |
Java中int型的数据,在C中就会用jint表示。
还有很关键的一点是方法签名,方法签名的作用是唯一确定一个方法,因为方法可以有重载,所以仅靠方法的名称是无法准确定位一个方法的,这个时候就需要方法签名了,方法签名实际上就是方法返回值和参数表的组合,它的规则如下:
字段ID如何获取呢?继续查阅文档,我们又找到了GetStaticFieldID(jclass clazz, const char* name, const char* sig)函数,它的三个参数分别是需要获取成员变量的类,成员变量名和签名。
与此相同,JNIEnv中还提供了很多很多获取变量信息、获取方法信息的函数。
#include
extern "C"
JNIEXPORT jint JNICALL
Java_com_tustcs_ndktest_NativeUtil_calculate(JNIEnv *env, jclass type, jint arg0, jint arg1,
jint symbol) {
if(symbol == env->GetStaticIntField(type,env->GetStaticFieldID(type,"ADD","I")))
return arg0 + arg1;
else if(symbol == env->GetStaticIntField(type,env->GetStaticFieldID(type,"SUB","I")))
return arg0 - arg1;
else if(symbol == env->GetStaticIntField(type,env->GetStaticFieldID(type,"MULTI","I")))
return arg0 * arg1;
else if(symbol == env->GetStaticIntField(type,env->GetStaticFieldID(type,"DIVISION","I")))
return arg0 / arg1;
}
然后在CMakeLists.txt中添加路径,再去MainActivity调用。。嗯,大功告成。
今天附上关于静态块和成员变量初始化的小知识:
public class InitTest {
public static int sInt1 = 10;
public static int sInt2;
public int mInt1 = 30;
public int mInt2;
//局部代码块
{
if(mInt1 == 30) {
System.out.println("成员变量mInt1已完成初始化:mInt1 = " + mInt1);
}
mInt2 = 40;
System.out.println("代码块mInt2初始化:mInt2 = " + mInt2);
}
//静态块
static{
sInt2 = 20;
System.out.println("静态块sInt2初始化:sInt2 = " + sInt2);
}
public static void print() {
System.out.println("静态方法:print()调用");
}
}
主方法执行:
public static void main(String[] args) {
InitTest.print();
//InitTest test = new InitTest();
}
在主函数调用InitTest的静态方法,结果如下:
我们可以看到,调用类的静态方法不会调用局部代码块,而会先调用静态块。
去掉注释,实例化一个类试试
public static void main(String[] args) {
//InitTest.print();
InitTest test = new InitTest();
}
我们可以看到,实例化一个类时,会优先调用静态块,再调用代码块和给成员变量赋值。
那么,代码块和给成员变量赋值哪个先执行呢?
答案是从头开始执行,程序运行到哪里,就先调用哪里,按顺序执行。