类路径与模块路径是并行机制而非替代关系:类路径将所有类塞入未命名模块,无访问控制;模块路径基于module-info.class构建模块图,强制依赖声明与包可见性控制。

类路径(-cp 或 --class-path)和模块路径(-p 或 --module-path)不是新旧替代关系,而是两套并行、语义完全不同的类加载机制。核心区别不在“怎么写路径”,而在“JVM怎么理解它”。
本质定位不同
类路径只管“找类”:JVM 把它下面所有 JAR 和目录里的 .class 文件,统统塞进一个叫 unnamed module(未命名模块)的大筐里,不问来源、不验身份、不控访问——只要 public 就能被反射或直接 new 出来。
模块路径只管“建模块图”:JVM 一旦看到 -p,就启用模块系统(JPMS),严格按 module-info.class 解析依赖、校验导出、控制包可见性。没有 module-info.class 的 JAR 塞进去,会变成自动模块(automatic module),名字取自文件名,但所有包默认导出,封装形同虚设。
放错位置的后果很直接
- JAR 里有
module-info.class,却放进-cp→ 模块声明完全失效,requires和exports被忽略,强封装崩塌 - JAR 里没有
module-info.class,却硬塞进-p→ 变成自动模块,可能引发 split package(同名包分散在多个模块)、反射访问失控等问题 - 同名类同时出现在两个路径 →
-p优先,-cp中那个被静默跳过,哪怕它是你刚编译的新版本
依赖和访问规则截然相反
类路径下:所有 public 类全局可访问,无依赖声明,运行时才发现 NoClassDefFoundError。
立即学习“Java免费学习笔记(深入)”;
模块路径下:必须显式 requires 才能用别人模块的类;必须 exports 才能让别人用你的包;未 opens 的包,反射访问会抛 IllegalAccessException。
两者共存时,模块内代码默认看不到 -cp 里的类(除非通过 requires 引用自动模块),而 -cp 里的代码可以用 Class.forName 加载模块里的 public 类——但模块语义全部丢失。
怎么判断该放哪?只看一个东西
执行:jar -tf your.jar | grep module-info.class
- 有输出 → 必须走
-p - 无输出 → 只能走
-cp
别猜、别试、别靠经验——这是唯一硬性标准。混用路径是多数 Module not found、Unable to derive module descriptor 和 IllegalAccessError 的根源。


















