核心思想
package 的核心思想是 解决命名冲突 和 实现代码的模块化管理,它就像你电脑里的文件夹,把不同用途的文件(代码)分门别类地存放起来。

你可能会有两个不同的项目,都创建了一个名为 User 的类,如果没有包,它们就会放在同一个目录下,导致冲突,但有了包,一个可以是 com.projectA.model.User,另一个是 com.projectB.entity.User,它们就可以完美共存。
声明包
在 Java 源代码文件(.java 文件)的开头,使用 package 关键字来声明该文件所属的包。
语法:
package <包名>;
规则:

- 必须是源文件的第一行非注释代码。
- 一个文件只能声明一个包。
- 包名通常使用小写字母,以避免与类名、接口名冲突。
- 包名采用 倒置的域名 命名法,这是一种约定俗成的规范,可以确保包名的唯一性,如果你的域名是
mycompany.com,那么你的包名可以是com.mycompany.project.utils。
示例:
创建一个名为 com.example.model 的包,并在其中创建一个 Person.java 文件。
// File: Person.java
package com.example.model;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
目录结构
Java 编译器有一个硬性规定:包的声明必须与文件在文件系统中的目录结构完全一致。
这意味着:
- 包名
com.example.model对应的目录结构是com/example/model/。 Person.java文件必须存放在com/example/model/这个目录下。
一个典型的项目结构可能如下:

my_project/
└── src/
└── com/
└── example/
└── model/
└── Person.java // 包声明: package com.example.model;
编译
编译 Java 带包的文件时,关键在于如何告诉编译器你的源文件根目录在哪里,编译器需要根据 package 声明来创建正确的目录结构。
在源文件所在的目录下编译
假设你的当前工作目录是 my_project/src/。
- 打开终端/命令行,进入
my_project/src目录。cd /path/to/my_project/src
- 执行
javac命令,编译器会读取Person.java中的package声明,并自动在当前目录下创建com/example/model/子目录,然后将编译后的.class文件放进去。javac com/example/model/Person.java
- 编译成功后,你会看到生成的目录结构:
my_project/ └── src/ └── com/ └── example/ └── model/ ├── Person.java └── Person.class // 新生成的字节码文件
在任意目录下编译(更常用、更规范)
这是更推荐的做法,因为它与构建工具(如 Maven, Gradle)的工作方式一致。
假设你的项目结构是:
my_project/
└── src/
└── com/
└── example/
└── model/
└── Person.java
-
打开终端,进入项目的根目录
my_project/。cd /path/to/my_project
-
使用
-d选项指定输出目录。 表示当前目录,src是源代码根目录。javac -d . src/com/example/model/Person.java
javac: 编译器命令。-d .: 告诉编译器将生成的.class文件及其包目录结构输出到当前目录 () 下。src/com/example/model/Person.java: 要编译的源文件路径。
-
编译成功后,你会看到在
my_project根目录下生成了一个com文件夹:my_project/ ├── src/ │ └── com/ │ └── example/ │ └── model/ │ └── Person.java └── com/ <-- 编译器生成的 └── example/ └── model/ └── Person.class这种方式非常清晰,
src用于存放源代码,com(或其他你指定的目录,如target) 用于存放编译后的产物。
运行
运行带包的类时,同样需要指定完整的包名,你不能直接进入 com/example/model 目录去运行 Person.class,因为这样会找不到类。
命令格式:
java <完整包名>.<类名>
继续上面的例子:
你的当前工作目录仍然是 my_project/,Person.class 文件位于 my_project/com/example/model/Person.class。
-
错误的做法:
# 错误!找不到或无法加载主类 Person java com.example.model.Person
为什么会错?因为
java命令会在当前目录 (my_project) 下寻找com/example/model/Person.class,但实际路径是my_project/com/example/model/Person.class,它找不到。 -
正确的做法: 你需要告诉
java命令,你的类的根目录是哪里,使用-classpath(或其简写-cp) 选项。# 正确! java -classpath com com.example.model.Person
-classpath com: 告诉java虚拟机,类的根目录是my_project/com。com.example.model.Person: 告诉虚拟机要运行哪个类。
运行后,控制台会输出:
Hello, my name is null and I am 0 years old.(因为没有传递构造参数,所以是默认值)
或者,更通用的做法: 如果你的编译输出目录是当前目录 (),
-classpath就应该是 。java -classpath . com.example.model.Person
使用其他包中的类
当你想在 com.example.model 包中的 Person 类里,使用 java.util 包里的 ArrayList 时,你需要:
-
使用全限定名
package com.example.model; import java.util.ArrayList; // 更推荐的方式 public class Person { private String name; // ... public void listHobbies() { // 使用全限定名 java.util.ArrayList<String> hobbies1 = new java.util.ArrayList<>(); // 或者使用 import 语句(更推荐) ArrayList<String> hobbies2 = new ArrayList<>(); } } -
使用
import语句import语句写在package声明之后,类定义之前,它只是帮你简化了代码,告诉编译器去哪里找这个类,并不会影响运行时的行为。// File: Person.java package com.example.model; import java.util.ArrayList; // 导入 ArrayList 类 public class Person { // ... }
总结与最佳实践
| 步骤 | 命令/操作 | 说明 |
|---|---|---|
| 目录结构 | src/com/example/model/Person.java |
包名必须与目录结构一致。 |
| 编译 | javac -d . src/com/example/model/Person.java |
在项目根目录编译,-d . 指定输出目录为当前目录。 |
| 运行 | java -classpath com com.example.model.Person |
使用 -classpath 指定类的根目录,然后用完整包名+类名运行。 |
| 导入类 | import java.util.ArrayList; |
在 package 之后,类定义之前,使用 import 简化代码。 |
现代开发工具的做法:
在实际开发中,我们几乎不会手动使用 javac 和 java 命令,我们会使用 Maven 或 Gradle 这样的构建工具。
- Maven: 你只需要在
pom.xml中定义项目坐标(GroupId, ArtifactId, Version),Maven 会自动管理包结构。groupId对应包名的前几部分(如com.example)。artifactId对应项目名。- Maven 会强制你将源代码放在
src/main/java目录下,编译后的输出在target/classes目录下。 - 你只需在
src/main/java下按照包名创建目录结构即可。 - 运行时,Maven 会自动设置好
classpath,你只需运行mvn compile和mvn exec:java等命令即可。
手动编译和运行是理解 Java package 机制的最佳途径,而掌握构建工具则是现代 Java 开发的必备技能。
