1. C调用java static方法:staticMethod
- 在Simple1 定义静态方法 给C调用:
public static String getUUID()
定义native方法:private native static void callStaticMethod();
- Simple1, 生成native对应的头文件(com_darren_ndk_day13_Simple1.h)。
- 将头文件拷贝到VisualStudio中,先拷贝到项目目录,头文件--添加--现有项,选择头文件。
- 生成.dll动态库。重新生成解决方案.
- 在Eclipse中,引入动态库:
System.load("D:/Java/NDK_Day13.dll"); // 加载VisualStudio生成的动态库.dll - 在Simple中,调用
callStaticMethod();
让C层 调用Java的 getUUID方法,打印uuid出来:
// c_uuid = 5f531097-e666-41d3-8d71-47499aa33b77
2.jni基本数据类型
2.1 JNIEnv里面的所有方法,先去明确目的,从下往上写。
2.2 了解JNIEnv的基本数据类型:
jstring --> java String
jint --> java int
jintArray --> java int []
jdouble --> java double
jfloat --> java float
jobject --> java Object
2.3 回收内存: (*env)->ReleaseStringUTFChars(env,j_uuid,c_uuid);
2.4 方法签名(descriptor),尽量记住常用的方法签名,属性签名。
括号中是参数,后面是返回值。
eg:()Ljava/lang/String;
对应方法:public static String getUUID(){}
签名:(IF)Lcom/darren/ndk/day13/Point;
// L开头,分号结尾,中间是全类名,点改成/
对应方法:public static Point test(int x, float y){}
对象数组:Object[] --> [L全类名;
void --> V
签名:([Ljava/lang/String;)V
对应的方法:public static void main(String[] args){}
3. 常量指针 和 指针常量
常量变量:被常量const修饰的变量,不能再次被赋值。
常量指针:int const * n_p
const 在*之前,就是常量指针。指针的地址是可以被再次赋值(可以修改的);
指针地址上面的值(变量)是不能被修改的,常量指针的常量是不能被改变的。
指针常量:int * const n_p
const 在之后,就是指针常量。指针的地址是不可以被再次赋值(吧可以修改的);
指针地址上面的值(变量)能够被修改,指针常量的指针地址是不能改变的。
总结:一个值可以改变,一个指针的地址可以改变。谁在前面谁就不能变。
应用场景:传char 给别人使用,要值不能被修改或 指针的地址不能被修改。避免重新分配地址(改动)。
void main(){
// 常量,不能去修改
const int number = 100;
// number = 200; // 常量不能修改
int number1 = 100;
int number2 = 200;
// 常量指针
// int const * n_p = &number2;
// n_p = &number1;
// printf("n_p = %p",n_p); // 地址是可以重新被赋值的
// *n_p = 300; 值是不能改的
// 指针常量
int * const n_p = &number2;
// n_p = &number1; 地址是不能被重新赋值
*n_p = 300;
printf("number2 = %d", number2);
// getchar();
}
4.Native 层构建Java对象。
怎样在C层构建java对象,并返回给 java层。
1.通过全类名找到: jclass point_clz = (env)->FindClass(env,"com/darren/ndk/day13/Point");
2.获取构造函数:jmethodID j_mid = (env)->GetMethodID(env,point_clz, "<init>", "(II)V");
3.调用构造函数:jobject point = (*env)->NewObject(env, point_clz, j_mid, 11,22); // 默认坐标(11,22)
5.设置属性练习。
VisualStudio中代码
// com_darren_ndk_day13_Simple1.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_darren_ndk_day13_Simple1 */
#ifndef _Included_com_darren_ndk_day13_Simple1
#define _Included_com_darren_ndk_day13_Simple1
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_darren_ndk_day13_Simple1
* Method: callStaticMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_darren_ndk_day13_Simple1_callStaticMethod
(JNIEnv *, jclass);
JNIEXPORT jobject JNICALL Java_com_darren_ndk_day13_Simple1_createPoint
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
// Sample.c
#include "com_darren_ndk_day13_Simple1.h"
// jni的实现方法,调用Java层的getUUID方法
JNIEXPORT void JNICALL Java_com_darren_ndk_day13_Simple1_callStaticMethod
(JNIEnv *env, jclass jclz){
// 2.获取 methodId, 括号中是参数,后面是返回值类型(String全名)
jmethodID j_mid = (*env)->GetStaticMethodID(env,jclz,"getUUID","()Ljava/lang/String;");
// 1.调用 getUUID 的方法 static,得到jstring
jstring j_uuid = (*env)->CallStaticObjectMethod(env, jclz,j_mid);
// jstring -> c_str
char* c_uuid = (*env)->GetStringUTFChars(env,j_uuid,NULL);
// 回收,字符串回收 jstring、char*
(*env)->ReleaseStringUTFChars(env,j_uuid,c_uuid);
printf("c_uuid = %s", c_uuid); // 得到uuid,打印。
}
// C 构建一个Java对象返回。
JNIEXPORT jobject JNICALL Java_com_darren_ndk_day13_Simple1_createPoint
(JNIEnv *env, jclass jclz){
// jclz 是Java那边的调用者 -> Simple1
// 获取 Point 的 class, name = "全类名", 点改成斜线/
jclass point_clz = (*env)->FindClass(env,"com/darren/ndk/day13/Point");
// 构建 java 层的 Point 对象,构造函数的id , 构造方法名称(百度) <init>固定。不要写Point
jmethodID j_mid = (*env)->GetMethodID(env,point_clz, "<init>", "(II)V");
jobject point = (*env)->NewObject(env, point_clz, j_mid, 11,22); // 默认坐标(11,22)
// 练习一下:1.给 y 重新赋值 ?调用 setY 方法
j_mid = (*env)->GetMethodID(env, point_clz,"setY","(I)V");
/* va_list 集合,后面的参数是集合
void (JNICALL *CallVoidMethodV)
(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
// jvalue,后面的参数是jvalue
void (JNICALL *CallVoidMethodA)
(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
*/
(*env)->CallVoidMethod(env, point,j_mid, 33); // 调用point的方法,setY修改Y坐标。
printf("after CallVoidMethod.\n");
// 作业:2.直接给属性赋值,x=106.
jfieldID fieldID = (*env)->GetFieldID(env, point_clz, "x", "I");
printf("fieldID \n");
// 给fieldID属性赋值
(*env)->SetIntField(env, point, fieldID, 106);
printf("fieldID SetIntField \n");
// 释放本地引用
(*env)->DeleteLocalRef(env, point_clz);
printf("DeleteLocalRef \n");
return point; // 返回构建的java对象。
}
void main(){
// 常量,不能去修改
const int number = 100;
// number = 200;
int number1 = 100;
int number2 = 200;
// 常量指针
// int const * n_p = &number2; // 地址
// n_p = &number1;
// printf("n_p = %p",n_p); // 地址是可以重新被赋值的
// *n_p = 300; // 值是不能改的
// 指针常量
int * const n_p = &number2;
// n_p = &number1; 地址是不能被重新赋值
*n_p = 300;
printf("number2 = %d", number2);
getchar();
}
// 有一些追求,多花时间,学东西。
Eclipse 项目代码
之前生成的.h头文件: com_darren_ndk_day13_Simple1.h;
VisualStudio 生成的.dll文件:D:/Java/NDK_Day13.dll
package com.darren.ndk.day13;
import java.util.UUID;
public class Simple1 {
public static void main(String[] args) {
// callStaticMethod(); // C调用 native方法,native调用Java的 static方法。
// c_uuid = 5f531097-e666-41d3-8d71-47499aa33b77
Point point = createPoint();
System.out.println("point: x = "+point.getX()+" , y = "+point.getY());
// point: x = 106 , y = 33
// android 用反射,jni 设置属性值,反射的原理。for循环构建反射对象,还是直接调用set方法。jni比反射快。
}
// 创建Point对象。
private native static Point createPoint();
private native static void callStaticMethod();
// 小的思考:静态方法获取uuid的方法,然后再 C调用这个方法获取uuid(Java实现更简单)
public static String getUUID() {
return UUID.randomUUID().toString();
}
public static Point test(int x, float y){
return null;
}
static{
// System.load("C:/Users/hcDarren/Desktop/android/NDK/NDK_Day13/x64/Debug/NDK_Day13.dll");
System.load("D:/Java/NDK_Day13.dll"); // 加载VisualStudio生成的动态库.dll
}
}
网友评论