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

JNI FindClass无法识别Jar包中带包路径的类问题求助

问题描述

无法通过JNI的FindClass函数找到Jar包中的类。未打包Jar时(类文件不在子文件夹)能成功找到,但嵌套在多级子文件夹的类无法检测到。

测试过程

  1. 创建jvmtest.java文件:
public class jvmtest
{
  public static void main(String[] args)
  {
    System.out.println("Hello from jvmtest main");
  }

  public class innerjvmtest
  {
    public void hello()
    {
      System.out.println("Hello from innerjvmtest");
    }
  }
}
  1. 将文件放入com文件夹,在该文件夹内执行编译命令:
javac jvmtest.java
  1. 创建包含com子文件夹的Jar包:
jar cvf jvmtest.jar com/*.class
  1. JNI测试代码(Main.cpp):
#include <jni.h>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{  
  JavaVM *vm;
  JNIEnv *env;
  JavaVMInitArgs vm_args;
  vm_args.version = JNI_VERSION_1_6;
  JavaVMOption *options = new JavaVMOption[1];
  options[0].optionString = "-Djava.class.path=jvmtest.jar";
  vm_args.nOptions = 1;
  vm_args.options = options;
  vm_args.ignoreUnrecognized = false;
  // 初始化JVM
  jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
  if (res != JNI_OK)
  {
    std::cout << "Failed to load JVM" << std::endl;
  }
  std::cout << "JVM loaded: JNI Version ";
  jint ver = env->GetVersion();
  std::cout << ((ver>>16)&0x0f) << "."<<(ver&0x0f) << std::endl;

  jclass cls = env->FindClass("com/jvmtest");
  if(cls == NULL)
  {
    std::cout << "ERROR: outer class not found !" << std::endl;
  }
  else
  {
    std::cout << "SUCCESS: Found the outer class !" << std::endl;
  }
  
  env->ExceptionDescribe();
}

程序输出及异常

输出内容:

JVM loaded: JNI Version 9.0 ERROR: outer class not found !

抛出异常:

Exception in thread "main" java.lang.NoClassDefFoundError: jvmtest (wrong name: com/jvmtest)
at java.lang.ClassLoader.defineClass1(java.base@9-internal/Native Method)
at java.lang.ClassLoader.defineClass(java.base@9-internal/ClassLoader.java:939)
at java.security.SecureClassLoader.defineClass(java.base@9-internal/SecureClassLoader.java:152)
at jdk.internal.loader.BuiltinClassLoader.defineClass(java.base@9-internal/BuiltinClassLoader.java:553)
at jdk.internal.loader.BuiltinClassLoader.access$200(java.base@9-internal/BuiltinClassLoader.java:88)
at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:466)
at jdk.internal.loader.BuiltinClassLoader$3.run(java.base@9-internal/BuiltinClassLoader.java:460)
at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
at jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(java.base@9-internal/BuiltinClassLoader.java:459)
at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@9-internal/BuiltinClassLoader.java:406)
at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@9-internal/BuiltinClassLoader.java:364)
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@9-internal/ClassLoaders.java:184)
at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:419)

疑问:为什么提示com/jvmtest是错误名称?如何用JNI的FindClass检测Jar包中的类?


解决方案

报错的核心原因是:Java类未声明包名,但你将class文件放到了com目录下,导致JVM识别的类名称与你传入FindClass的路径不匹配。

Java包机制的核心要求:

  • 类文件的存放路径必须与包名完全对应
  • 类源代码中必须显式声明package语句

修复步骤

  1. 修改jvmtest.java,添加包声明:
package com; // 新增包声明

public class jvmtest
{
  public static void main(String[] args)
  {
    System.out.println("Hello from jvmtest main");
  }

  public class innerjvmtest
  {
    public void hello()
    {
      System.out.println("Hello from innerjvmtest");
    }
  }
}
  1. 重新编译:
    回到com文件夹的上级目录执行编译,确保编译器自动维护包对应的目录结构:
javac com/jvmtest.java
  1. 重新打包Jar:
    同样在上级目录执行打包命令,确保Jar中包含完整的包目录结构:
jar cvf jvmtest.jar com
  1. 保持JNI代码不变,重新运行程序,FindClass("com/jvmtest")即可成功找到目标类。

补充说明

  • JNI中FindClass的参数格式是用斜杠/分隔的全限定类名,对应Java中点.分隔的全限定名(比如com.jvmtest对应com/jvmtest)
  • 如果类未声明包名,即使放在子目录中,JVM仍会认为它属于默认包,此时FindClass需用"jvmtest"作为参数,但这种情况下不能将类放在子目录中打包,否则会出现名称不匹配错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:45:55