md文件相关操作语法参考
java之jvm的javap命令
获取class字节码相关、类信息、方法签名(javap s xxx.class)
本文包括内容
配置或小知识点
AndroidStudio中需要打印C中的日志配置或小知识点
jni方法的各个部分所代表的的含义
本地代码的注册多线程相关
JNI多线程注意事项以及
配置或小知识点
在AndroidStudio中需要打印C中的日志:
android{
defaultConfig {
//新版中其实默认已经支持了。只需要使用android/log.h即可打印日志
ndk {
ldLibs = "log" //此配置是指添加ndk的日志支持.实际使用:liblog.so
}
}
}
JNI相关知识点解释
示例方法:
//实现Java_com_test01_Test_firstTest方法
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv *, jobject){
Console::WriteLine(L"第一个Jni小程序");
}
1、jni方法的各个部分所代表的的含义
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);
JNIEXPORT
:在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。void
:这个学过编程的人都知道,当然是方法的返回值了。JNICALL
:这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。Java_com_test01_Test_firstTest
:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。JNIEnv
* env:这个env可以看做是Jni接口本身的一个对象,在上一篇中提到的jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)jobject obj
:刚才在Test类的main方法中有这样一段代码:
Test t=new Test();
t.firstTest();
这个jobject需要两种情况分析。上段代码中firstTest方法是一个非静态方法,在Java中要想调用它必须先实例化对象,然后再用对象调用它,那这个时候jobject就可以看做Java类的一个实例化对象,也就是obj就是t。如果firstTest是一个静态方法,那么在Java中,它不是属于一个对象的,而是属于一个类的,Java中用Test.firstTest()这样的方式来调用,这个时候jobject就可以看做是java类的本身,也就是obj就是Test.class。
1、本地方法注册
本地代码的注册方式有两种:
- 在执行本地方法前,在Java代码里使用语句
System.loadLibrary("foo")
加载本地方法所有的链接库;- 在本地方法的实现里,需要用到其他链接库里的本地方法时,第一种方法就不适用了,比如,在本地方法里声明另一个本地方法
void JNICALL g_impl(JNIEnv *env, jobject self);
但它的实现是在另一个链接库里实现的,则需要使用下面的代码来作为这个方法的实现:
//这里某一个本地方法里的代码,省略了其他部分代码
JNINativeMethod nm;
nm.name = "g";//需要使用的其他链接库里的本地方法的名字
/* 方法的描述,如返回值,参数等 */
nm.signature = "()V";
nm.fnPtr = g_impl;//在这里的本地方法的声明的名字
//注册g_impl方法
(*env)->RegisterNatives(env, cls, &nm, 1);
方法g_imlp
的声明并不需要遵循JNI的命名规范,因为这只是调用时的方法指针,并不需要展开代码(调用这个方法时,实际调用的是另一个链接库里名为g
的JNI方法),所有不需要使用JNIEXPORT
,但需要遵循JNI的调用规范。
多线程之间ENV环境变量的约束:
在本地方法里写有关多线程的代码时,需要知道下面几个约束:
(注:JVM可以跨线程共享)
- 一个JNIEnv指针只在与它关联的线程里有效,也就是说,在线程间传递JNIEnv指针和在多线程环境里通过缓存来使用它是不允许和不安全的。JVM在同一个线程里多次调用同一个本地方法时传递的是同一个JNIEnv指针,但在不同的线程里调用同一个本地方法时传递的是不同的JNIEnv指针。
- 本地引用只在创建它的线程里有效,也就是说你不能在线程间传递本地引用。因为在多线程的环境里可能会使用到相同的引用,因此我们需要将本地引用转型为全局引用
在任意线程中获取env环境对象:
JavaVM *jvm; /* already set */
f(){
JNIEnv *env;
//建立当前线程的连接。将环境变量变量关联到当前线程,也就是获取到当前线程
(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
... /* use env */
//使用完成之后一定要调用此方法释放jvm和当前线程的连接
javaVM->DetachCurrentThread();
}