最近 IntelliJ IDEA 2026.3 EAP发布了 有一个很有意思的 新特性,标题是:
解决那些包名和目录结构对不上、还用通配符导入的类。
IDEA想来是严守规矩的一个工具,但是这个新特性让IDEA开始 能认这种“不守规矩”的代码
先看看它说的是什么情况
假设你有两个 Java 文件,放在同一个源目录下。第一个文件长这样:
packageorg.classa;publicclassClassA{publicvoidfoo(){}}注意,它的包名是org.classa,但文件可能放在src/根目录下,而不是src/org/classa/。这是不按 Maven/Gradle 标准目录结构走的写法。
第二个文件是测试类:
packageexamples;importorg.classa.*;publicclassClassTest{voidtest(){ClassAa=newClassA();org.classa.ClassAa1=neworg.classa.ClassA();}}它用import org.classa.*;通配符导入了第一个文件所在的包。
为什么 Java 代码可以不按标准目录走
这里得先澄清一个常见的误解:Maven/Gradle 的目录结构,不是 Java 语言的规定,而是构建工具的约定。
Java 语言本身只规定了一件事:一个.java文件里,package声明写的是什么,这个类的全限定名就是什么。编译器(javac)根本不关心你的文件放在哪个文件夹里。你把ClassA.java放在src/根目录,只要它里面写着package org.classa;,编译出来的ClassA.class就在org/classa/目录下。
那为什么大家都按src/main/java/org/classa/ClassA.java来放?
因为Maven 和 Gradle 把“目录结构”当成了“包名”的默认来源。你用 Maven 构建项目时,它会在src/main/java下按包名扫目录。如果你的ClassA.java放在根目录但声明了package org.classa,Maven 在编译时可能找不到它,或者编译出来的 class 文件位置和预期不符,导致运行时ClassNotFoundException。
所以,目录结构是构建工具的“寻址规则”,不是 Java 语言的“强制语法”。
那为什么还有人写不按目录走的代码?
- 不用 Maven/Gradle 的项目:纯
javac命令行编译的小项目,目录随便放,只要-sourcepath指对了就行。 - 遗留项目迁移:老项目从 Ant 或 Eclipse 迁过来,目录结构历史遗留,包名和目录早就不一致了。
- 代码生成器产物:有些工具生成的 Java 文件,包名按业务逻辑写,目录按另一套逻辑放。
- 教学和实验代码:为了演示方便,所有类塞进一个源目录,包名随便写。
- 多语言混编:目录结构按 Kotlin 或 Scala 的惯例组织,Java 文件的包名自然对不上。
这些项目不一定“规范”,但它们真实存在,而且能正常编译运行。
过去在 IDEA 里,这个文件会报两个错,而且也符合Java开发者的直觉:
Cannot resolve symbol 'classa'——import org.classa.*;这一行飘红,IDEA 不认为org.classa是个能导入的包。Cannot resolve symbol 'ClassA'——下面ClassA a = new ClassA();也飘红,因为通配符导入没被解析,ClassA这个名字找不到。
但诡异的是,最后一行org.classa.ClassA a1 = new org.classa.ClassA();却完全不报错。
为什么全限定名能用,通配符不能用
当你写new org.classa.ClassA()时,IDEA 走的是全限定名解析。它不需要知道org.classa是不是一个“合法的包”,它只需要在项目的符号索引里找到一个名字叫org.classa.ClassA的类。只要这个类存在,它就能解析。
但当你写import org.classa.*;时,IDEA 走的是包解析。它会去检查:org.classa在项目的包结构里是不是一个真实的、有对应目录的包?如果目录结构和包名对不上,IDEA 就认为这个包“不存在”,通配符导入就失败。
于是同一个类,用全限定名能引用,用通配符导入就报错。
如此一来IDEA就变成了:从“按目录结构找包”变成“按符号声明找包”。
对用户来说,这意味着:
- 包名和目录对不上的项目,通配符导入不再飘红。
- 不用为了迁就 IDE,去重构一个本来能跑的项目。
- 全限定名和通配符导入的行为终于一致了——都能用,没有双标。
这个 新特性 让我想起一句话:工具应该适应代码,而不是让代码适应工具。
现在它终于要改了。不为什么,就因为真实世界的代码,从来不是照着教科书写的。