Java最全JNI开发之方法签名与Java通信(二),2024Java高级进阶学习资料

最后

一次偶然,从朋友那里得到一份“java高分面试指南”,里面涵盖了25个分类的面试题以及详细的解析:JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、Spring、Spring Boot、Spring Cloud、RabbitMQ、Dubbo 、MyBatis 、ZooKeeper 、数据结构、算法、Elasticsearch 、Kafka 、微服务、Linux。

这不,马上就要到招聘季了,很多朋友又开始准备“金三银四”的春招啦,那我想这份“java高分面试指南”应该起到不小的作用,所以今天想给大家分享一下。

image

请注意:关于这份“java高分面试指南”,每一个方向专题(25个)的题目这里几乎都会列举,在不看答案的情况下,大家可以自行测试一下水平 且由于篇幅原因,这边无法展示所有完整的答案解析

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

int f (int i, Object object) (ILjava/lang/Object;)I

void set (byte[ ] bytes) ([B)V

二、JNI实现java与c/c++相互通讯

2.1、签名映射表

JNI获取Java类的方法和字段,都需要一个很重要的参数,就是Java类的方法和字段的签名。所以最好能够记住它们。

“Lfully-qualified-class;”->L类全名; 例如Java String类对应的签名是Ljava/lang/String;

“[type”->java数组的签名,例如int[]的签名[I,java Stringg[]的签名是[Ljava/lang/String;

“(arg-types)ret-type”->(函数参数)返回值,()只是所有参数,ret-type是返回类型签名例如

void test(String msg)对应的签名是(Ljava/lang/String;)V

long f(int n,String s,int[] arr)对应的签名(Ijava/lang/String;[I)J

void f()对应用的签名()V

2.2、jni是如何访问java中的方法和字段

jni的native接口中,第一个参数为JNI接口指针(JNIEnv),第二个参数根据native方法是静态还是非静态而不同。非静态native方法的第二个参数是对该对象的引用,静态方法的第二参数是对其java类的引用。其与参数对应Java方法参数。

从上述描述中,如果是非静态的,我们可以拿到对象的引用。通过对象的引用,我们可以访问该对象的字段和方法。如果是静态的,我们可以访问该对象的静态方法和静态字段。那么jni中具体是如何访问的呢?我们将在下面的章节通过实例来介绍

2.3、jni访问java中的方法

java代码

public void show(String s){
Log.i(“MainActivity”,“show:”+s);
}
public native void showString(String s);

jni代码

//访问Java中的show方法
JNIEXPORT void JNICALL Java_com_zzy_ndkdemo_MainActivity_showString(JNIEnv *env, jobject instance, jstring s) {

//获取instance的类名称
jclass cls = (*env)->GetObjectClass(env,instance);
if(cls==NULL)
{
LOGD(“Class %s not found”);
}

//获取方法ID,第二个参数为类名称,第三个参数为方法名称,第三个参数为方法签名,详细参见签名对照表
jmethodID id =(*env)->GetMethodID(env,cls,“show”,“(Ljava/lang/String;)V”);
if(id !=NULL)
{
//访问方法,第二个为类实例,第三个参数为方法ID,第四和第四以后为方法参数,
// 根据返回类型不同,调用不同的CallXXXMethod方法,xxx返回类型
(*env)->CallVoidMethod(env,instance,id,s);
}
}

2.4、jni访问java中的静态方法

java代码

public static void showStatic(String s){
Log.i(“MainActivity”,“show static:”+s);
}
public native void showStaticString(String s);

jni代码

//访问Java中的showStatic静态方法
JNIEXPORT void JNICALL Java_com_zzy_ndkdemo_MainActivity_showStaticString(JNIEnv *env, jobject instance, jstring s) {

//获取instance的类名称
jclass cls = (*env)->GetObjectClass(env,instance);
if(cls==NULL)
{
LOGD(“Class %s not found”);
}

//获取静态方法ID,第二个参数为类名称,第三个参数为方法名称,第三个参数为方法签名,详细参见签名对照表
jmethodID id =(*env)->GetStaticMethodID(env,cls,“showStatic”,“(Ljava/lang/String;)V”);
if(id !=NULL)
{
//访问方法,第二个为类名称,第三个参数为方法ID,第四和第四以后为方法参数,
// 根据返回类型不同,调用不同的CallStaticXXXMethod方法,xxx返回类型
(*env)->CallStaticVoidMethod(env,cls,id,s);
}
}

1、从中我们可以看出静态方法比非静态方法的访问多加了一个static,访问函数由类实例,变成类引用。

2、如果静态方法不存在instance类中,我们可以通过FindClass进行访问,其中第二个参数为类的全路径

jclass cls = (*env)->FindClass(env, “com/zzy/ndkdemo/JniDemo”);
if (cls == NULL) {
LOGD(“Class %s not found”);
}

2.5、jni访问java中的字段

java代码

User user = new User();
user.name = “zhang san”;
user.age = 30;
User.token = “2018-2011—3223”;

String name = showUserName(user);
Log.i(“MainActivity”,“show name:”+name);
public native String showUserName(User user);

jni代码

//访问User中的字段name
JNIEXPORT jstring JNICALL Java_com_zzy_ndkdemo_MainActivity_showUserName(JNIEnv *env, jobject instance, jobject user) {

//获取User的类名称
jclass cls=(*env)->GetObjectClass(env,user);
if (cls == NULL) {
LOGD(“Class %s not found”);
return NULL;
}

//获取字段ID,第二个参数类名称,第三个参数字段名,第三个参数字段签名,详细参见签名对照表
jfieldID id = (*env)->GetFieldID(env,cls,“name”,“Ljava/lang/String;”);
if(id==NULL)
{
LOGD(“Field token not found”);
return NULL;
}
//获取字段内容,调用GetXXXField,xxx为字段类型。除基本类型外,其他的都使用GetObjectField
jstring name=(jstring) (*env)->GetObjectField(env,user,id);
return name;
}

2.6、jni访问Java中的静态字段

java代码

User user = new User();
user.name = “zhang san”;
user.age = 30;
User.token = “2018-2011—3223”;
String token =showUserStaticToken(user);
Log.i(“MainActivity”,“show static token:”+token);
public native String showUserStaticToken(User user);

jni代码

//访问User中的静态字段Token
JNIEXPORT jstring JNICALL Java_com_zzy_ndkdemo_MainActivity_showUserStaticToken(JNIEnv *env, jobject instance, jobject user) {

//获取User的类名称
jclass cls=(*env)->GetObjectClass(env,user);
if (cls == NULL) {
LOGD(“Class %s not found”);
return NULL;
}

//获取静态字段ID,第二个参数类名称,第三个参数字段名,第三个参数字段签名,详细参见签名对照表
jfieldID id = (*env)->GetStaticFieldID(env,cls,“token”,“Ljava/lang/String;”);
if(id==NULL)
{
LOGD(“Field token not found”);
return NULL;
}

//获取字段内容,调用GetStaticXXXField,xxx为字段类型。除基本类型外,其他的都使用GetStaticObjectField
jstring token=(*env)->GetStaticObjectField(env,cls,id);
return token;
}

1、从中我们可以看出静态字段比非静态字段的访问多加了一个static,访问函数由类实例,变成类引用。

2、如果静态字段中不存在instance类中,我们可以通过FindClass进行访问,其中第二个参数为类的全路径

jclass cls = (*env)->FindClass(env, “com/zzy/ndkdemo/User”);
if (cls == NULL) {
LOGD(“Class %s not found”);
}

2.7、jni中更新java的字段内容

java代码

User user = updateUser(user);
Log.i(“MainActivity”,“updateUser name:”+user.name+" age:“+user.age+” token:"+User.token);
public native User updateUser(User user);

jni代码

//更新user内容
JNIEXPORT jobject JNICALL Java_com_zzy_ndkdemo_MainActivity_updateUser(JNIEnv *env, jobject instance,jobject user)
{
//获取User的类名称
jclass cls=(*env)->GetObjectClass(env,user);
if (cls == NULL) {
LOGD(“Class %s not found”);
return NULL;
}

//获取每一个字段ID,第二个参数类名称,第三个参数字段名,第三个参数字段签名,详细参见签名对照表
jfieldID idName = (*env)->GetFieldID(env,cls,“name”,“Ljava/lang/String;”);
jfieldID idAge = (*env)->GetFieldID(env,cls,“age”,“I”);
jfieldID idToken = (*env)->GetStaticFieldID(env,cls,“token”,“Ljava/lang/String;”);

//将cha字符串转成jstring
jstring name = (*env)->NewStringUTF(env, “李四”);
jstring token = (*env)->NewStringUTF(env, “new token”);

//更新字段内容,调用setxxxField,xxx为字段类型,如果是静态字段还需要加上static
//第二个参数为需要修改的类实例或则类名,第三个参数为字段Id,第四个参数为需要修改的内容
(*env)->SetObjectField(env,user,idName,name);
(*env)->SetIntField(env,user,idAge,20);
(*env)->SetStaticObjectField(env,cls,idToken,token);

return user;
}

2.8、jni中创建java类实例

java代码

User user = createUser();
Log.i(“MainActivity”,“createUser name:”+user.name+" age:“+user.age+” token:"+User.token);
public native User createUser();

jni代码

//创建user实例
JNIEXPORT jobject JNICALL Java_com_zzy_ndkdemo_MainActivity_createUser(JNIEnv *env, jobject instance)
{
//在指定路径查找到USer类名称
jclass cls = (*env)->FindClass(env, “com/zzy/ndkdemo/User”);
if (cls == NULL) {
LOGD(“Class %s not found”);
}

//获取User类的构造方法ID,第二个参数为类名称,第三个参数固定为""
//第四个参数为构造函数签名,详细参见签名对照表
jmethodID id= (*env)->GetMethodID(env, cls, “”, “()V”);

//实例化User类,第二个参数类名称,第三个参数构造方法ID
jobject user = (*env)->NewObject(env, cls, id);
if (user == NULL) {
LOGD(“Create User failed”);
}

//获取每一个字段ID,第二个参数类名称,第三个参数字段名,第三个参数字段签名,详细参见签名对照表
jfieldID idName = (*env)->GetFieldID(env,cls,“name”,“Ljava/lang/String;”);
jfieldID idAge = (*env)->GetFieldID(env,cls,“age”,“I”);
jfieldID idToken = (*env)->GetStaticFieldID(env,cls,“token”,“Ljava/lang/String;”);

//将cha字符串转成jstring
jstring name = (*env)->NewStringUTF(env, “王五”);
jstring token = (*env)->NewStringUTF(env, “second token”);

//赋予字段内容,调用setxxxField,xxx为字段类型,如果是静态字段还需要加上static
//第二个参数为需要修改的类实例或则类名,第三个参数为字段Id,第四个参数为需要修改的内容
(*env)->SetObjectField(env,user,idName,name);
(*env)->SetIntField(env,user,idAge,10);
(*env)->SetStaticObjectField(env,cls,idToken,token);

学习分享,共勉

这里是小编拿到的学习资源,其中包括“中高级Java开发面试高频考点题笔记300道.pdf”和“Java核心知识体系笔记.pdf”文件分享,内容丰富,囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。同时还有Java进阶学习的知识笔记脑图(内含大量学习笔记)!

资料整理不易,读者朋友可以转发分享下!

Java核心知识体系笔记.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

中高级Java开发面试高频考点题笔记300道.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

架构进阶面试专题及架构学习笔记脑图

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

Java架构进阶学习视频分享

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

脑图**

[外链图片转存中…(img-1ur2e3sq-1715318437670)]

Java架构进阶学习视频分享

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值