You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI内部类方法中接收外部类this而非内部类this的问题

JNI中内部类调用外部类native方法时this参数为外部类实例的原因及解决方案

原因分析:这是符合规范的有意设计

你遇到的现象完全符合JNI和Java语言规范,核心原因如下:

  • jni_print是外部类OuterClass的成员native方法,JNI中实例方法的第一个jobject this参数,始终指向该方法所属类的实例,而非调用该方法的对象实例。
  • Java非静态内部类默认持有外部类的引用,当内部类调用外部类的成员方法时,本质是通过持有的外部类实例来执行该方法。这和普通Java方法的行为完全一致:比如在InnerClass里调用OuterClass的普通成员方法,方法内的this同样是外部类实例,而非内部类实例。

关于文档说明

JNI规范明确规定:实例native方法的第一个参数是方法所属类的对象引用(对应Java方法中的this);Java语言规范也定义了内部类访问外部类成员的机制。只需将两者结合理解,就能解释你遇到的现象。

解决方案

如果需要在JNI中获取内部类的实例,有两种可行方式:

  1. 手动传递内部类this作为参数(即你当前代码的做法)
    你已经在InnerClass.printThis()中把内部类的this传给jni_print,JNI里通过第二个参数obj就能拿到内部类实例,这是完全合理的实现方式。
  2. 将native方法定义在内部类中
    修改代码把jni_print定义为InnerClass的native方法,此时JNI的this参数就会是内部类的实例:
    public final class OuterClass {
        static {
            System.loadLibrary("jtest");
        }
        
        static private void print(Object o1, Object o2) {
            System.out.println("this = " + o1 + ", arg1 = " + o2);
        }
        
        public OuterClass() {
        }
    
        public void printThis() {
            jni_print(this);
        }
    
        private native void jni_print(Object obj);
    
        public final class InnerClass {
            private native void jni_print_inner(Object obj);
            
            public InnerClass() {
            }
    
            public void printThis() {
                jni_print_inner(this);
            }
        }
    }
    
    对应的JNI注册代码需要调整为注册到OuterClass$InnerClass类:
    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    
    #define OUTER_CLASS "OuterClass"
    #define INNER_CLASS "OuterClass$InnerClass"
    
    static void jni_print_outer(JNIEnv *env, jobject this, jobject obj) {
        jclass cls = (*env)->FindClass(env, OUTER_CLASS);
        jmethodID printID = (*env)->GetStaticMethodID(env, cls, "print", "(Ljava/lang/Object;Ljava/lang/Object;)V");
        (*env)->CallStaticVoidMethod(env, cls, printID, this, obj);
    }
    
    static void jni_print_inner(JNIEnv *env, jobject this, jobject obj) {
        jclass cls = (*env)->FindClass(env, OUTER_CLASS);
        jmethodID printID = (*env)->GetStaticMethodID(env, cls, "print", "(Ljava/lang/Object;Ljava/lang/Object;)V");
        (*env)->CallStaticVoidMethod(env, cls, printID, this, obj);
    }
    
    static JNINativeMethod outer_funcs[] = {
        { "jni_print", "(Ljava/lang/Object;)V", (void *)&jni_print_outer },
    };
    
    static JNINativeMethod inner_funcs[] = {
        { "jni_print_inner", "(Ljava/lang/Object;)V", (void *)&jni_print_inner },
    };
    
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
        JNIEnv *env;
        jclass  outer_cls;
        jclass  inner_cls;
        jint    reg_res;
    
        (void)reserved;
    
        if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK)
            return -1;
    
        outer_cls = (*env)->FindClass(env, OUTER_CLASS);
        if (outer_cls == NULL)
            return -1;
    
        reg_res = (*env)->RegisterNatives(env, outer_cls, outer_funcs, sizeof(outer_funcs)/sizeof(outer_funcs[0]));
        if (reg_res != 0)
            return -1;
    
        inner_cls = (*env)->FindClass(env, INNER_CLASS);
        if (inner_cls == NULL)
            return -1;
    
        reg_res = (*env)->RegisterNatives(env, inner_cls, inner_funcs, sizeof(inner_funcs)/sizeof(inner_funcs[0]));
        if (reg_res != 0)
            return -1;
    
        return JNI_VERSION_1_8;
    }
    
    // JNI_OnUnload 代码略
    

内容的提问来源于stack exchange,提问作者PoltoS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:33:17