2

我有想要在 JNI 中访问的公共内部类。GetFieldID 在访问内部类的 fieldId 时返回 null

下面是代码

public class classA{
    public class classB{
    public int b1;
    }
   public int a1;
   public classB B;
}

注意:当我在类文件上运行 javap -s 时,我得到以下输出

public class level1.level2.level3.classA{
public int a1;
    descriptor : I
public level1.level2.level3.classA$classB B;
    descriptor : Llevel1/level2/level3/classA$classB;

这是调用本机函数的类。

public class extraclass{
    private native int myfunction1(classA A);
    public int extrafunction(classA A){
        myfunction1(A);
    }
}

本机代码

JNIEXPORT jint JNICALL myfunction1( JNIEnv *env, jobject obj ,jobject A)
{
    jclass cls = (*env)->GetObjectClass( env, A);
    jfieldID ja1,jB;
    int a1;

    ja1 = (*env)->GetFieldID( env, cls, "a1","I" );
    a1  = (*env)->GetIntField(env, config, ja1); // This works good.

    jB = (*env)->GetFieldID( env, cls, "B","Llevel1/level2/level3/classA$classB;" ); 
    // <<< Its crashing here with "JNI DETECTED ERROR IN APPLICATION: JNI GetFieldID called with pending exception 'java.lang.NoSuchFieldError'"

}

我也尝试了以下选项但失败了

jB = (*env)->GetFieldID( env, cls, "B","LclassA$classB;" );  

有人可以建议如何获取 classB 的字段 id 并访问 b1。

4

1 回答 1

1

这个很老了,但也许有人会发现它很有用。

在您的情况下,您似乎在包名称、字段名称中有些“混乱”。

它与以下代码完美配合:

.
|-- Makefile
|-- README.md
|-- c
|   `-- level1_level2_level3_extraclass.c
|-- java
|   `-- level1
|       `-- level2
|           `-- level3
|               |-- classA.java
|               `-- extraclass.java
|-- lib
`-- target

其中classA.java包含

package level1.level2.level3;

public class classA {

  public class classB {
    public int b1 = 42;
  }

  public int a1 = 44;
  public classB B = new classB();

}

并且extraclass.java是一种形式:

package level1.level2.level3;

import level1.level2.level3.classA;

public class extraclass {

    static {

      System.loadLibrary("Extra");
    }

    private native int myfunction1(classA A);

    public int extrafunction(classA A){
        return myfunction1(A);
    }

    public static void main(String [] arg) {

      extraclass ex = new extraclass();
      classA a = new classA();

      System.out.println("Result: " + ex.extrafunction(a));
    }
}

谈到C代码 - 它与您提供的内容略有不同。

#include <jni.h>

JNIEXPORT jint JNICALL Java_level1_level2_level3_extraclass_myfunction1( JNIEnv *env, jobject obj, jobject objA)
{
    jclass cls = (*env) -> GetObjectClass( env, objA );

    jfieldID fid_a1   = (*env) -> GetFieldID( env, cls, "a1", "I" );
    int valA          = (*env) -> GetIntField( env, objA, fid_a1);

    jfieldID fid_B     = (*env) -> GetFieldID( env, cls, "B", "Llevel1/level2/level3/classA$classB;");
    jobject B_Val      = (*env) -> GetObjectField( env, objA, fid_B );

    jclass clsClassB   = (*env) -> GetObjectClass( env, B_Val );

    jfieldID fid_b1    = (*env) -> GetFieldID( env, clsClassB, "b1", "I" );
    int valB           = (*env) -> GetIntField( env, B_Val, fid_b1 );

    return valB + valA;

}

无论如何,稍微清理一下代码,并确保所有包名称都到位,一切都按预期工作。

你可以在这里找到蒸馏版本:https ://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo063

于 2019-11-19T14:57:29.120 回答