为何带包声明的Java类无法引用Jar根目录下的无包类?
问题分析与解决:命名包类无法引用Jar包默认包中的类
问题现象
当Java类属于命名包时,无法引用Jar包根目录下(默认包/未命名包)的类;但该类处于默认包时,却能正常引用。复现脚本如下:
构建包含默认包类的Jar包脚本
#!/bin/bash # Create directory structure mkdir -p projA/src/java/org/example mkdir -p projA/out/artifacts # Create Java source files cat > projA/src/java/Class2.java << EOF public class Class2 { // Empty class } EOF cat > projA/src/java/org/example/Class1.java << EOF package org.example; public class Class1 { // Empty class } EOF # Compile Java files find projA/src/java -name "*.java" > sources.txt javac -d projA/target @sources.txt # Create JAR file jar cf projA/out/artifacts/projA.jar -C projA/target . # View contents of JAR file tar tf projA/out/artifacts/projA.jar
引用Jar包的测试脚本
#!/bin/bash # Create directory structure mkdir -p ProjB/src/java/org/fred # Create Java source files cat > ProjB/src/java/Main2.java << EOF public class Main2 { public static void main(String[] args) { Class2 class2 = new Class2(); } } EOF cat > ProjB/src/java/org/fred/Main1.java << EOF package org.fred; import org.example.Class1; public class Main1 { public static void main(String[] args) { Class1 class1 = new Class1(); // Class2 class2 = new Class2(); // <--- 取消注释后触发编译错误 } } EOF # Compile Java files javac -d ProjB/target -cp projA/out/artifacts/projA.jar ProjB/src/java/*.java ProjB/src/java/org/fred/*.java # Run the classes java -cp ProjB/target:projA/out/artifacts/projA.jar Main2 java -cp ProjB/target:projA/out/artifacts/projA.jar org.fred.Main1
取消Main1.java中标记行的注释后,编译报错:
ProjB/src/java/org/fred/Main1.java:12: error: cannot find symbol Class2 class2 = new Class2();
原因解释
这是Java语言的固有规则:
- 默认包(未命名包)的类之间可以直接访问:
Main2和Class2都在默认包,属于同一个未命名的命名空间,public类无需import就能直接引用。 - 命名包的类无法引用未命名包中的类:Java语法里没有合法的方式来import默认包的类(import语句必须指定包名,而默认包没有包名),编译器会直接找不到符号。
解决办法
修改Jar包结构(推荐):把
Class2移到一个正式的命名包中(比如org.example),然后在Main1里添加import语句:import org.example.Class2;重新编译打包后,命名包的
Main1就能正常引用Class2了。临时 workaround(不推荐):把
Main1也移到默认包中,但这种方式只适合小型测试项目,大型项目使用默认包会导致类名冲突、无法模块化等问题。
内容的提问来源于stack exchange,提问作者abulka
相关产品推荐
相关产品推荐

