JNI FindClass无法识别Jar包中带包路径的类问题求助
问题描述
无法通过JNI的FindClass函数找到Jar包中的类。未打包Jar时(类文件不在子文件夹)能成功找到,但嵌套在多级子文件夹的类无法检测到。
测试过程
- 创建
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"); } } }
- 将文件放入
com文件夹,在该文件夹内执行编译命令:
javac jvmtest.java
- 创建包含
com子文件夹的Jar包:
jar cvf jvmtest.jar com/*.class
- 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语句
修复步骤
- 修改
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"); } } }
- 重新编译:
回到com文件夹的上级目录执行编译,确保编译器自动维护包对应的目录结构:
javac com/jvmtest.java
- 重新打包Jar:
同样在上级目录执行打包命令,确保Jar中包含完整的包目录结构:
jar cvf jvmtest.jar com
- 保持JNI代码不变,重新运行程序,
FindClass("com/jvmtest")即可成功找到目标类。
补充说明
- JNI中
FindClass的参数格式是用斜杠/分隔的全限定类名,对应Java中点.分隔的全限定名(比如com.jvmtest对应com/jvmtest) - 如果类未声明包名,即使放在子目录中,JVM仍会认为它属于默认包,此时
FindClass需用"jvmtest"作为参数,但这种情况下不能将类放在子目录中打包,否则会出现名称不匹配错误
内容的提问来源于stack exchange,提问作者mya
相关产品推荐
相关产品推荐

