package 是 Java 中强制性的结构声明,必须位于源文件首行(除注释外),绑定路径、决定可见性、影响 import;未声明则归入默认包,无法被 import;包名须与目录结构严格一致。

Java 中的 package 关键字不是“用来利用”的工具,而是强制性的结构声明 —— 它直接绑定文件路径、决定类可见性、影响 import 行为。跳过或写错 package 声明,编译器会报错,IDE 会找不到类,运行时可能抛 NoClassDefFoundError。
package 声明必须是源文件第一行(除注释外)
很多初学者在 package 前加了 import 或空行,导致编译失败:
import java.util.*; // ❌ 错误:package 必须在最前 package com.example.util;
正确写法:
// 可以有注释
// 但不能有任何语句(包括 import、class、空语句)
package com.example.util;
public class StringUtils { ... }
-
package语句只能出现一次,且必须位于非空白、非注释的第一行 - 如果文件里有多个类(不推荐),它们全部属于该
package - 没写
package的类会被归入“默认包”(unnamed package),无法被其他包 import,也不适合任何正式项目
包名必须与目录结构严格一致
这是 Java 编译器和 JVM 查找类的核心规则。例如声明了 package com.example.dao;,那么这个 .java 文件就必须放在项目根目录下的 com/example/dao/ 子目录中。
常见错误现象:
- IDE 显示类“找不到”,但文件明明存在 → 实际路径是
src/utils/MyClass.java,却写了package com.example.util; - Maven 编译通过,但运行时报
ClassNotFoundException→target/classes下生成的.class文件没落到对应目录树 - 用
javac手动编译时提示 “class file contains wrong class” → 包名和路径不匹配,或类名与文件名不一致
验证方式:编译后检查 .class 文件是否出现在 com/example/dao/MyDao.class 这样的嵌套路径下。
import 和全限定名的选择直接影响可读性与耦合度
import 不是必需的,但它决定了你写代码时要不要反复敲长名字。
- 用
import com.example.service.UserService;后,可直接写new UserService() - 不用 import,就得写全限定名:
new com.example.service.UserService()—— 冗长,且一旦包名变更,所有调用点都要改 - 避免滥用
import com.example.*;:它不会提升性能,但会让 IDE 难以判断具体用了哪个类,也容易引发同名类冲突(比如两个包都叫Response) - Java 标准包(如
java.lang.*)自动导入,无需显式写import
注意:import 只影响编译期符号解析,对运行时类加载无影响;它也不改变访问权限 —— 如果目标类不是 public,即使 import 了也无法访问。
包私有(default)访问权限是最容易被忽略的控制点
没加 public、protected 或 private 的类、方法、字段,默认就是“包级可见”。这意味着:
- 只有同一个
package下的类能直接访问它 - 跨包调用时,哪怕子类继承了该类,也无法访问其 default 成员(
protected才可以) - 很多人误以为“不写修饰符 = public”,结果在另一个包里 new 不了类、调不了方法,却查不出原因
- 测试类(如 JUnit)若不在同一包下,就访问不到被测类的 default 方法 —— 这是单元测试写不下去的常见根源
所以,当你希望某个工具类只供本模块内部使用,又不想暴露给整个项目时,不加 public 就是天然的封装手段;但反过来,如果你打算让别人用你的类,第一件事就是确保类本身是 public 的。










