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

通过JNI获取Java应用中所有类及类内全部方法

JNI+C++ 实现Java类名枚举与方法信息打印

一、枚举Java应用中所有类名(解决Minecraft主类找不到问题)

你当前通过线程上下文类加载器查找minecraft.client.Minecraft失败,大概率是类名包路径错误(正确路径应为net.minecraft.client.Minecraft),同时可以通过枚举类加载器已加载的所有类来排查问题。以下是修改后的setupClassLoader函数,添加类枚举逻辑:

static jobject classLoader;
static jmethodID mid_findClass;

static void printClassLoaderClasses(JNIEnv* env, jobject classLoaderObj) {
    jclass c_ClassLoader = env->FindClass("java/lang/ClassLoader");
    jclass c_Class = env->FindClass("java/lang/Class");
    
    // 获取类加载器的getDefinedClasses方法(返回该加载器定义的所有类)
    jmethodID mid_getDefinedClasses = env->GetMethodID(c_ClassLoader, "getDefinedClasses", "()[Ljava/lang/Class;");
    // 获取Class的getName方法
    jmethodID mid_getName = env->GetMethodID(c_Class, "getName", "()Ljava/lang/String;");
    // 获取父类加载器方法
    jmethodID mid_getParent = env->GetMethodID(c_ClassLoader, "getParent", "()Ljava/lang/ClassLoader;");

    // 枚举当前类加载器的类
    jobjectArray classes = (jobjectArray)env->CallObjectMethod(classLoaderObj, mid_getDefinedClasses);
    if (classes) {
        jint classCount = env->GetArrayLength(classes);
        for (int j = 0; j < classCount; j++) {
            jobject cls = env->GetObjectArrayElement(classes, j);
            jstring classNameStr = (jstring)env->CallObjectMethod(cls, mid_getName);
            const char* className = env->GetStringUTFChars(classNameStr, nullptr);
            
            printf("Loaded class: %s\n", className);
            
            // 检查是否是目标Minecraft类
            if (strcmp(className, "net.minecraft.client.Minecraft") == 0) {
                classLoader = env->NewGlobalRef(classLoaderObj); // 保存全局引用
                printf("Found target class loader!\n");
            }
            
            env->ReleaseStringUTFChars(classNameStr, className);
            env->DeleteLocalRef(cls);
        }
        env->DeleteLocalRef(classes);
    }

    // 递归枚举父类加载器的类
    jobject parentLoader = env->CallObjectMethod(classLoaderObj, mid_getParent);
    if (parentLoader) {
        printClassLoaderClasses(env, parentLoader);
        env->DeleteLocalRef(parentLoader);
    }

    env->DeleteLocalRef(c_ClassLoader);
    env->DeleteLocalRef(c_Class);
}

static void setupClassLoader()
{
    JNIEnv* env = Java::Env;
    jclass c_Thread = env->FindClass("java/lang/Thread");
    jclass c_Map = env->FindClass("java/util/Map");
    jclass c_Set = env->FindClass("java/util/Set");
    jclass c_ClassLoader = env->FindClass("java/lang/ClassLoader");

    jmethodID mid_getAllStackTraces = env->GetStaticMethodID(c_Thread, "getAllStackTraces", "()Ljava/util/Map;");
    jmethodID mid_keySet = env->GetMethodID(c_Map, "keySet", "()Ljava/util/Set;");
    jmethodID mid_toArray = env->GetMethodID(c_Set, "toArray", "()[Ljava/lang/Object;");
    jmethodID mid_getContextClassLoader = env->GetMethodID(c_Thread, "getContextClassLoader", "()Ljava/lang/ClassLoader;");
    mid_findClass = env->GetMethodID(c_ClassLoader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
    jmethodID mid_currentThread = env->GetStaticMethodID(c_Thread, "currentThread", "()Ljava/lang/Thread;");

    jobject obj_stackTracesMap = env->CallStaticObjectMethod(c_Thread, mid_getAllStackTraces);
    jobject obj_threadsSet = env->CallObjectMethod(obj_stackTracesMap, mid_keySet);

    jobjectArray threads = (jobjectArray) env->CallObjectMethod(obj_threadsSet, mid_toArray);
    jint szThreads = env->GetArrayLength(threads);

    for (int i = 0; i < szThreads; i++) {
        jobject thread = env->GetObjectArrayElement(threads, i);
        jobject classLoaderObj = env->CallObjectMethod(thread, mid_getContextClassLoader);

        if (classLoaderObj) {
            // 枚举当前类加载器下的所有类
            printClassLoaderClasses(env, classLoaderObj);
            
            // 尝试直接查找目标类(修正包路径)
            jstring className = env->NewStringUTF("net.minecraft.client.Minecraft");
            jobject minecraftClass = env->CallObjectMethod(classLoaderObj, mid_findClass, className);

            if (minecraftClass) {
                classLoader = env->NewGlobalRef(classLoaderObj);
                printf("Successfully found Minecraft class!\n");
                env->DeleteLocalRef(minecraftClass);
                env->DeleteLocalRef(className);
                break;
            }
            env->DeleteLocalRef(className);
        }

        env->DeleteLocalRef(thread);
    }

    env->DeleteLocalRef(threads);
    env->DeleteLocalRef(obj_threadsSet);
    env->DeleteLocalRef(obj_stackTracesMap);
    env->DeleteLocalRef(c_Thread);
    env->DeleteLocalRef(c_Map);
    env->DeleteLocalRef(c_Set);
    env->DeleteLocalRef(c_ClassLoader);
}

关键修改点:

  • 新增printClassLoaderClasses递归函数,枚举类加载器及其父加载器的所有已定义类
  • 修正Minecraft类的包路径为net.minecraft.client.Minecraft
  • 使用NewGlobalRef保存类加载器引用,避免局部引用被回收

二、获取指定类的所有方法信息

在成功获取目标jclass后,可通过Java反射API枚举类的所有方法(包括私有方法),并打印方法名和返回类型:

inline static jclass clazz;

bool Java::AssignClass(std::string name, jclass& out)
{
    JNIEnv* env = Java::Env;
    jstring className = env->NewStringUTF(name.c_str());
    jobject findClass = env->CallObjectMethod(classLoader, mid_findClass, className);

    if (findClass) {
        out = (jclass)env->NewGlobalRef(findClass); // 保存全局引用
        env->DeleteLocalRef(findClass);
        env->DeleteLocalRef(className);
        return true;
    }
    env->DeleteLocalRef(className);
    return false;
}

void PrintClassMethods(jclass clazz) {
    JNIEnv* env = Java::Env;
    jclass c_Class = env->FindClass("java/lang/Class");
    jclass c_Method = env->FindClass("java/lang/reflect/Method");

    // 获取类的getDeclaredMethods方法(返回所有声明的方法,含私有)
    jmethodID mid_getDeclaredMethods = env->GetMethodID(c_Class, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
    // 获取Class的getName方法
    jmethodID mid_classGetName = env->GetMethodID(c_Class, "getName", "()Ljava/lang/String;");
    // 获取Method的getName方法
    jmethodID mid_methodGetName = env->GetMethodID(c_Method, "getName", "()Ljava/lang/String;");
    // 获取Method的getReturnType方法
    jmethodID mid_methodGetReturnType = env->GetMethodID(c_Method, "getReturnType", "()Ljava/lang/Class;");

    // 获取类名并打印
    jstring classNameStr = (jstring)env->CallObjectMethod(clazz, mid_classGetName);
    const char* className = env->GetStringUTFChars(classNameStr, nullptr);
    printf("\n=== Methods of class: %s ===\n", className);
    env->ReleaseStringUTFChars(classNameStr, className);
    env->DeleteLocalRef(classNameStr);

    // 遍历所有方法
    jobjectArray methods = (jobjectArray)env->CallObjectMethod(clazz, mid_getDeclaredMethods);
    jint methodCount = env->GetArrayLength(methods);
    for (int k = 0; k < methodCount; k++) {
        jobject methodObj = env->GetObjectArrayElement(methods, k);
        
        // 获取方法名
        jstring methodNameStr = (jstring)env->CallObjectMethod(methodObj, mid_methodGetName);
        const char* methodName = env->GetStringUTFChars(methodNameStr, nullptr);
        
        // 获取返回类型名称
        jobject returnTypeClass = env->CallObjectMethod(methodObj, mid_methodGetReturnType);
        jstring returnTypeNameStr = (jstring)env->CallObjectMethod(returnTypeClass, mid_classGetName);
        const char* returnTypeName = env->GetStringUTFChars(returnTypeNameStr, nullptr);
        
        printf("  %s -> %s\n", methodName, returnTypeName);
        
        // 释放资源
        env->ReleaseStringUTFChars(methodNameStr, methodName);
        env->ReleaseStringUTFChars(returnTypeNameStr, returnTypeName);
        env->DeleteLocalRef(methodObj);
        env->DeleteLocalRef(returnTypeClass);
        env->DeleteLocalRef(methodNameStr);
        env->DeleteLocalRef(returnTypeNameStr);
    }

    env->DeleteLocalRef(methods);
    env->DeleteLocalRef(c_Class);
    env->DeleteLocalRef(c_Method);
}

// 使用示例
int main() {
    setupClassLoader();
    if (Java::AssignClass("net.minecraft.client.Minecraft", clazz)) {
        PrintClassMethods(clazz);
    }
    return 0;
}

关键说明:

  • 使用getDeclaredMethods获取类所有声明的方法(包括私有、保护),若仅需公共方法可替换为getMethods
  • 所有JNI局部引用需及时释放,避免内存泄漏
  • 类和类加载器引用使用NewGlobalRef保存,确保跨函数调用有效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 20:35:55