Java的包 (Package)就是代码世界的"文件夹",它帮助我们把相关的类组织在一起,让代码结构清晰、易于管理
1.为什么需要包
1.1 避免命名冲突
没有包的情况:
Java
// 公司A的代码
class User { /* ... */ }
// 公司B的代码也用了同样的类名
class User { /* ... */ } // 冲突!无法共存
1.2 更好的组织
- 把所有用户相关的类放在
com.example.user包 - 把所有商品相关的类放在
com.example.product包 - 把所有订单相关的类放在
com.example.order包
2.包的概念
包就是一组相关类和接口的集合。它就像:
- 学校的班级:把同一学科的学生组织在一起
- 公司的部门:把相同职能的员工组织在一起
- 图书馆的分类:把同类书籍放在同一书架
包的声明和命名规范
3.1 如何声明包
Java
// 在Java文件的第一行(注释除外)声明包
package com.example.school;
public class Student {
// 类的内容
}
3.2 包的命名规范
Java
// 1. 使用小写字母
package com.example.mypackage; // ✅ 正确
package Com.Example.MyPackage; // ❌ 错误
// 2. 使用逆域名约定(最常用)
package com.google.common; // Google的通用库
package org.apache.commons; // Apache Commons
package java.util; // Java标准库
// 3. 多层包名用点分隔
package com.example.project.module.submodule;
// 4. 包名要有意义
package com.shop.user; // 用户相关
package com.shop.product; // 产品相关
package com.shop.order; // 订单相关
3.3 实际示例
项目结构:
Java
myproject/
├── src/
│ ├── com/
│ │ └── example/
│ │ └── school/
│ │ ├── Student.java
│ │ ├── Teacher.java
│ │ └── Course.java
│ └── Main.java
Student.java:
Java
// 声明包
package com.example.school;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("我是学生,我叫" + name + ",今年" + age + "岁");
}
}
Teacher.java:
Java
package com.example.school;
public class Teacher {
private String name;
private String subject;
public Teacher(String name, String subject) {
this.name = name;
this.subject = subject;
}
public void teach() {
System.out.println(name + "老师正在教" + subject);
}
}
4.包的导入
4.1 导入单个类
Java
// Main.java(不在包中,或在不同包中)
import com.example.school.Student;
import com.example.school.Teacher;
public class Main {
public static void main(String[] args) {
Student student = new Student("张三", 18);
Teacher teacher = new Teacher("李老师", "数学");
student.introduce();
teacher.teach();
}
}
4.2 导入整个包
Java
// 导入包中的所有类
import com.example.school.*;
public class Main {
public static void main(String[] args) {
// 可以使用包中的所有类
Student student = new Student("张三", 18);
Teacher teacher = new Teacher("李老师", "数学");
Course course = new Course("Java编程", 48);
student.introduce();
teacher.teach();
course.showInfo();
}
}
4.3 静态导入
Java
import static java.lang.Math.PI; // 导入静态常量
import static java.lang.Math.pow; // 导入静态方法
import static java.lang.System.out; // 导入静态成员
public class StaticImportDemo {
public static void main(String[] args) {
// 不用写 Math.PI,直接使用 PI
double radius = 5.0;
double area = PI * pow(radius, 2);
// 不用写 System.out,直接使用 out
out.println("圆的面积: " + area);
out.println("最大值: " + Math.max(10, 20)); // 也可以混用
}
}
4.4 不需要导入的情况
Java
public class NoImportNeeded {
public static void main(String[] args) {
// 1. 同包中的类不需要导入
// 如果这个类和Student在同一个包,可以直接使用
// 2. java.lang包中的类自动导入
String str = new String("Hello"); // java.lang.String
Integer num = 100; // java.lang.Integer
System.out.println("自动导入"); // java.lang.System
// 3. 使用完全限定名(不推荐,代码冗长)
java.util.ArrayList<String> list = new java.util.ArrayList<>();
java.util.Date date = new java.util.Date();
// 4. 处理同名冲突
java.sql.Date sqlDate = new java.sql.Date(0);
java.util.Date utilDate = new java.util.Date();
}
}
5.包与目录结构
5.1 必须匹配的目录结构
规则:包名必须与目录结构完全一致!
Java
项目结构:
src/
├── com/
│ └── example/
│ └── school/
│ ├── Student.java (package com.example.school;)
│ └── Teacher.java (package com.example.school;)
└── Main.java (没有包声明,或不同包)
编译和运行:
Java
# 编译(在src目录下)
javac com/example/school/Student.java
javac com/example/school/Teacher.java
javac Main.java
# 运行
java Main
5.2 使用IDE的项目结构
现代IDE(如IntelliJ IDEA、Eclipse)会自动管理包结构:
Java
myproject/
├── src/
│ └── main/
│ └── java/
│ ├── com/
│ │ └── example/
│ │ ├── school/
│ │ │ ├── Student.java
│ │ │ └── Teacher.java
│ │ └── utils/
│ │ └── StringUtil.java
│ └── Main.java
└── pom.xml 或 build.gradle
6.访问权限控制
6.1 Java的四种访问修饰符
Java
package com.example.school;
// 公共类:所有包都可以访问
public class Student {
// 公共字段:所有包都可以访问
public String publicField = "公共字段";
// 受保护字段:同包或子类可以访问
protected String protectedField = "受保护字段";
// 默认字段(包私有):只有同包可以访问
String defaultField = "默认字段";
// 私有字段:只有本类可以访问
private String privateField = "私有字段";
// 公共方法
public void publicMethod() {
System.out.println("公共方法");
// 可以访问所有字段
System.out.println(privateField);
}
// 受保护方法
protected void protectedMethod() {
System.out.println("受保护方法");
}
// 默认方法
void defaultMethod() {
System.out.println("默认方法");
}
// 私有方法
private void privateMethod() {
System.out.println("私有方法");
}
}
6.2 访问权限总结表
| 修饰符 | 同类 | 同包 | 子类 | 不同包 |
|---|---|---|---|---|
public |
✓ | ✓ | ✓ | ✓ |
protected |
✓ | ✓ | ✓ | ✗ |
| 默认(无) | ✓ | ✓ | ✗ | ✗ |
private |
✓ | ✗ | ✗ | ✗ |
6.3 实际应用示例
同包访问:
Java
// 在 com.example.school 包中
package com.example.school;
public class Course {
// 可以访问同包的Student的所有非私有成员
public void testAccess() {
Student student = new Student("测试", 20);
System.out.println(student.publicField); // ✓ 可以
System.out.println(student.protectedField); // ✓ 可以(同包)
System.out.println(student.defaultField); // ✓ 可以(同包)
// System.out.println(student.privateField); // ✗ 错误:私有
student.publicMethod(); // ✓ 可以
student.protectedMethod(); // ✓ 可以(同包)
student.defaultMethod(); // ✓ 可以(同包)
// student.privateMethod(); // ✗ 错误:私有
}
}
不同包访问:
Java
// 在不同包中
package com.example.test;
import com.example.school.Student;
public class TestClass {
public void testAccess() {
Student student = new Student("测试", 20);
System.out.println(student.publicField); // ✓ 可以
// System.out.println(student.protectedField); // ✗ 错误:不同包且非子类
// System.out.println(student.defaultField); // ✗ 错误:不同包
// System.out.println(student.privateField); // ✗ 错误:私有
student.publicMethod(); // ✓ 可以
// student.protectedMethod(); // ✗ 错误:不同包且非子类
// student.defaultMethod(); // ✗ 错误:不同包
// student.privateMethod(); // ✗ 错误:私有
}
}
子类访问(跨包):
Java
// 在不同包中创建Student的子类
package com.example.test;
import com.example.school.Student;
public class GraduateStudent extends Student {
public GraduateStudent(String name, int age) {
super(name, age);
}
public void testProtectedAccess() {
// 子类可以访问父类的protected成员
System.out.println(protectedField); // ✓ 可以(子类)
protectedMethod(); // ✓ 可以(子类)
// 但不能访问默认和私有成员
// System.out.println(defaultField); // ✗ 错误:不同包
// System.out.println(privateField); // ✗ 错误:私有
}
}
七、综合示例:完整的学校管理系统
项目结构:
text
复制下载
css
school-system/
├── src/
│ ├── com/
│ │ └── school/
│ │ ├── model/
│ │ │ ├── Person.java
│ │ │ ├── Student.java
│ │ │ ├── Teacher.java
│ │ │ └── Course.java
│ │ ├── service/
│ │ │ ├── StudentService.java
│ │ │ └── CourseService.java
│ │ ├── util/
│ │ │ └── DateUtil.java
│ │ └── Main.java
│ └── config.properties
代码实现:
Person.java(基类):
java
package com.school.model;
// 人员基类
public class Person {
protected String id; // 受保护,子类可以访问
protected String name;
private int age; // 私有,只有本类可以访问
public Person(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// 公共getter和setter
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0) {
this.age = age;
}
}
public void displayInfo() {
System.out.println("ID: " + id + ", 姓名: " + name + ", 年龄: " + age);
}
}
Student.java(学生类):
java
package com.school.model;
public class Student extends Person {
private String classId; // 班级ID
private double score; // 成绩
public Student(String id, String name, int age, String classId) {
super(id, name, age); // 调用父类构造方法
this.classId = classId;
this.score = 0.0;
}
// 可以访问父类的protected字段
public String getStudentInfo() {
return "学生[" + name + "](ID:" + id + ")";
}
// getter和setter
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public double getScore() {
return score;
}
public void setScore(double score) {
if (score >= 0 && score <= 100) {
this.score = score;
}
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.println("班级: " + classId + ", 成绩: " + score);
}
}
Teacher.java(教师类):
java
package com.school.model;
public class Teacher extends Person {
private String subject; // 教授科目
private String title; // 职称
public Teacher(String id, String name, int age, String subject, String title) {
super(id, name, age);
this.subject = subject;
this.title = title;
}
public void teach() {
System.out.println(title + name + "正在教授" + subject);
}
// getter和setter
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.println("科目: " + subject + ", 职称: " + title);
}
}
StudentService.java(服务类):
java
package com.school.service;
import com.school.model.Student;
import java.util.ArrayList;
import java.util.List;
public class StudentService {
private List<Student> students = new ArrayList<>();
// 添加学生
public void addStudent(Student student) {
students.add(student);
System.out.println("添加学生: " + student.getName());
}
// 查找学生
public Student findStudentById(String id) {
for (Student student : students) {
if (student.getId().equals(id)) {
return student;
}
}
return null;
}
// 显示所有学生
public void displayAllStudents() {
System.out.println("=== 所有学生 ===");
for (Student student : students) {
student.displayInfo();
}
}
// 统计平均分
public double calculateAverageScore() {
if (students.isEmpty()) {
return 0.0;
}
double total = 0.0;
for (Student student : students) {
total += student.getScore();
}
return total / students.size();
}
}
DateUtil.java(工具类):
java
package com.school.util;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
// 私有构造方法,防止被实例化
private DateUtil() {}
// 获取当前日期字符串
public static String getCurrentDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
// 获取当前时间字符串
public static String getCurrentTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
// 格式化日期
public static String formatDate(Date date, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(date);
}
}
Main.java(主类):
java
package com.school;
import com.school.model.Student;
import com.school.model.Teacher;
import com.school.service.StudentService;
import com.school.util.DateUtil;
public class Main {
public static void main(String[] args) {
System.out.println("=== 学校管理系统 ===");
System.out.println("当前日期: " + DateUtil.getCurrentDate());
System.out.println("当前时间: " + DateUtil.getCurrentTime());
// 创建学生
Student student1 = new Student("S001", "张三", 18, "一班");
Student student2 = new Student("S002", "李四", 19, "二班");
// 设置成绩
student1.setScore(85.5);
student2.setScore(92.0);
// 创建教师
Teacher teacher = new Teacher("T001", "王老师", 35, "数学", "高级教师");
// 显示信息
System.out.println("\n=== 人员信息 ===");
student1.displayInfo();
student2.displayInfo();
teacher.displayInfo();
// 教师授课
System.out.println("\n=== 教学安排 ===");
teacher.teach();
// 使用服务类
System.out.println("\n=== 学生管理 ===");
StudentService studentService = new StudentService();
studentService.addStudent(student1);
studentService.addStudent(student2);
studentService.displayAllStudents();
// 查找学生
System.out.println("\n=== 查找学生 ===");
Student found = studentService.findStudentById("S001");
if (found != null) {
System.out.println("找到学生: " + found.getName());
}
// 统计平均分
double average = studentService.calculateAverageScore();
System.out.println("\n平均分: " + average);
}
}
快速记忆口诀
- 包如文件夹 → 组织管理代码文件
- 逆域名命名 →
com.example.project - 导入需声明 → 不同包用
import - 访问有权限 →
public、protected、默认、private
最重要的三点
- 包是代码的组织单位 → 像文件夹整理文件一样整理类
- 包名必须与目录结构匹配 → 这是Java的硬性规定
- 合理使用访问修饰符 → 保护代码,控制可见性