[Java] [ Android ] [ JNI ] [ C/C++访问Java类或方法 ]

一、Native层访问Java类成员

Java层代码

class StaticFielcdAccess {
  private static int si;
  private native void accessField();
  public static void main(String args[]) {
    StaticFieldAccess c = new StaticFieldAccess();
    StaticFieldAccess.si = 100;
    c.accessField();
    System.out.println("In Java:");
    System.out.println(" StaticFieldAccess.si = " + si);
  }
  static {
    System.loadLibrary("StaticFieldAccess");
  }
}

JNI代码

JNIEXPORT void JNICALL
Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj)
{
  jfieldID fid; /* store the field ID */
  jint si;
  /* Get a reference to obj’s class */
  jclass cls = (*env)->GetObjectClass(env, obj);
  printf("In C:\n");
  /* Look for the static field si in cls */
  fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  if (fid == NULL) {
    return; /* field not found */
  }
  /* Access the static field si */
  si = (*env)->GetStaticIntField(env, cls, fid);
  printf(" StaticFieldAccess.si = %d\n", si);
  (*env)->SetStaticIntField(env, cls, fid, 200);
}

更多不同类型的域的获取,见jni.h

  jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
    jboolean    (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
    jbyte       (*GetByteField)(JNIEnv*, jobject, jfieldID);
    jchar       (*GetCharField)(JNIEnv*, jobject, jfieldID);
    jshort      (*GetShortField)(JNIEnv*, jobject, jfieldID);
    jint        (*GetIntField)(JNIEnv*, jobject, jfieldID);
    jlong       (*GetLongField)(JNIEnv*, jobject, jfieldID);
    jfloat      (*GetFloatField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;
    jdouble     (*GetDoubleField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__;

    void        (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
    void        (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
    void        (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
    void        (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
    void        (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
    void        (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
    void        (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
    void        (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat) __NDK_FPABI__;
    void        (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble) __NDK_FPABI__;

二、C/C++访问Java类方法

Java类的方法分三种,静态方法,实例方法,构造方法。还有一类特殊的,调用被子类覆盖的父类方法

1、调用实例方法

4.2.1 Calling Instance Methods
回调Java实例方法分两步:
• 首先通过GetMethodID在给定类中查询方法. 查询基于方法名称和签名
• 以返回值为void的方法为例,本地方法使用CallVoidMethod

JNIEXPORT void JNICALL
Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
  jclass cls = (*env)->GetObjectClass(env, obj);
  jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
  if (mid == NULL) {
    return; /* method not found */
  }
  printf("In C\n");
  (*env)->CallVoidMethod(env, obj, mid);
} 

2、调用静态方法

同实例方法,回调Java静态方法分两步:
• 首先通过GetStaticMethodID在给定类中查找方法
• 通过CallStaticMethod调用
静态方法与实例方法的不同,前者传入参数为jclass,后者为jobject

3、调用被子类覆盖的父类方法: JNI支持用CallNonvirtualMethod满足这类需求:

• GetMethodID获得method ID
• 调用CallNonvirtualVoidMethod, CallNonvirtualBooleanMethod
上述,等价于如下Java语言的方式:
super.f();
CallNonvirtualVoidMethod可以调用构造函数

4、调用构造方法

jstring 
MyNewString(JNIEnv *env, jchar *chars, jint len)
{
  jclass stringClass;
  jmethodID cid;
  jcharArray elemArr;
  jstring result;
  stringClass = (*env)->FindClass(env, "java/lang/String");
  if (stringClass == NULL) {
      return NULL; /* exception thrown */
  }
  /* Get the method ID for the String(char[]) constructor */
  cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
  if (cid == NULL) {
    return NULL; /* exception thrown */
  }
  /* Create a char[] that holds the string characters */
  elemArr = (*env)->NewCharArray(env, len);
  if (elemArr == NULL) {
    return NULL; /* exception thrown */
  }
  (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
  /* Construct a java.lang.String object */
  result = (*env)->NewObject(env, stringClass, cid, elemArr);
  /* Free local references */
  (*env)->DeleteLocalRef(env, elemArr);
  (*env)->DeleteLocalRef(env, stringClass);
  return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值