源本科技 | 码上会

Java 中的包

2025/12/27
30
0

学习目标

  • 理解包的核心作用:组织代码、避免命名冲突、控制访问权限

  • 掌握 内置包用户自定义包 的使用方式

  • 能够正确设计项目包结构并合理使用 import

  • 理解包与 访问修饰符(public / protected / default / private 的协同机制


什么是包

包(Package) 是 Java 提供的一种命名空间机制,用于将相关的类、接口、枚举和子包组织在一起。

核心目的

  • 避免类名冲突(如两个项目都有 Utils 类)

  • 控制类和成员的可见性

  • 提升代码的模块化与可维护性

类比理解:文件夹

就像电脑中的文件夹:

  • Documents/Work/Report.docx

  • Documents/Personal/Letter.docx

即使文件名相同(Report.docx vs Letter.docx),路径不同就不会混淆。Java 包就是类的“路径”。


包的类型

Java 中的包分为两类:

类型

说明

示例

内置包
Built-in Packages

Java 标准库提供的包

java.lang, java.util, java.io

用户自定义包
User-defined Packages

开发者自己创建的包

com.mycompany.utils, org.example.model


常见内置包

包名

功能说明

是否自动导入

java.lang

核心语言支持
String, Math, System, Object

✅ 是

java.util

工具类(集合框架、日期时间、随机数等)

❌ 否

java.io

输入 / 输出流操作

❌ 否

java.net

网络编程支持

❌ 否

java.awt javax.swing

图形用户界面(GUI)

❌ 否

示例:使用 java.util.Random

import java.util.Random; // 导入内置包中的 Random 类

public class Main {
    public static void main(String[] args) {
        Random rand = new Random();
        int number = rand.nextInt(100); // 生成 0~99 的随机整数
        System.out.println("随机数: " + number);
    }
}

java.lang 下的所有类(如 String, System)无需 import 即可直接使用。


用户自定义包

步骤 1:声明包

// 文件路径: src/com/myapp/Helper.java
package com.myapp;

public class Helper {
    public static void show() {
        System.out.println("来自 Helper 的问候!");
    }
}

包名规范

  • 全小写

  • 通常使用公司域名倒写:com.company.project.module

  • 如:com.alibaba.fastjson, org.apache.commons

步骤 2:编译与目录结构

project/
└── src/
    └── com/
        └── myapp/
            ├── Helper.java
            └── Test.java

重要:包名必须与文件系统目录结构完全一致

步骤 3:在其他类中使用

// 文件: src/com/myapp/Test.java
package com.myapp;

// 方式1:导入具体类
import com.myapp.Helper;

public class Test {
    public static void main(String[] args) {
        Helper.show(); // 输出:来自 Helper 的问候!
    }
}

或使用全限定名(不推荐,冗长):

public class Test {
    public static void main(String[] args) {
        com.myapp.Helper.show();
    }
}

导入的两种方式

方式

语法

说明

导入单个类

import java.util.ArrayList;

推荐:明确依赖,减少冲突

导入整个包

import java.util.*;

仅导入当前包下的类,不包含子包

示例对比

// 方式1:精确导入
import java.util.Vector;
import java.util.ArrayList;

public class Example {
    Vector v = new Vector();
    ArrayList list = new ArrayList();
}
// 方式2:通配符导入(慎用)
import java.util.*;

public class Example {
    Vector v = new Vector();
    ArrayList list = new ArrayList();
}

不推荐通配符导入的原因

  • 可能引发类名冲突(如 java.util.List vs java.awt.List

  • 降低代码可读性(不清楚具体用了哪些类)


包与访问修饰符

包直接影响类成员的可见性范围。以下是四种访问级别在包中的表现:

修饰符

同一类

同包

子类(不同包)

任意位置

private

default(无修饰符)

protected

public

关键点解析

  • default(包私有)
    只有同一个包内的类可以访问。这是实现“包内协作,对外隐藏”的关键。

  • protected
    同包 + 所有子类(即使子类在其他包)都能访问。

示例:default 访问控制

// 包: com.myapp.utils
package com.myapp.utils;

class InternalUtil { // default 访问权限
    static void helper() {
        System.out.println("内部工具方法");
    }
}

// 同包下的另一个类可以访问
class PublicAPI {
    void doSomething() {
        InternalUtil.helper(); // 允许
    }
}
// 包: com.other
package com.other;

import com.myapp.utils.InternalUtil;

public class External {
    void test() {
        // InternalUtil.helper(); // 编译错误!InternalUtil 不可见
    }
}

这正是包提供“访问保护”的体现。


包的命名

  1. 使用反向域名
    com.google.gson, org.springframework.boot

  2. 全小写,避免下划线 / 大写
    com.example.service
    Com.Example.Servicecom_example_service

  3. 按功能分层

    com.mybank
    ├── model        // 数据模型
    ├── service      // 业务逻辑
    ├── repository   // 数据访问
    └── controller   // Web 控制器
  4. 避免使用 Java 保留包名
    不要使用 java.*, javax.*, sun.*


静态导入

用于直接导入类的静态成员,避免重复写类名。

import static java.lang.Math.*;
import static java.lang.System.out;

public class MathExample {
    public static void main(String[] args) {
        double result = sqrt(pow(3, 2) + pow(4, 2)); // 直接调用 sqrt, pow
        out.println("结果: " + result); // 使用 out 代替 System.out
    }
}

谨慎使用:过度使用会降低代码可读性。


重点总结

  • 包是 Java 的命名空间 + 模块化单元

  • 内置包(如 java.util)提供标准功能,用户包用于组织自有代码

  • 包名 = 目录结构,必须严格对应

  • import 用于引入其他包中的类,推荐精确导入

  • default 访问修饰符实现“包内可见”,是封装的重要手段

  • 合理的包结构提升项目的可维护性、可读性与安全性


思考题

  1. 为什么 java.lang 包不需要显式 import?这对开发者有什么好处?

  2. 如果两个不同包中有同名类(如 com.a.Utilcom.b.Util),如何在同一个文件中同时使用它们?

  3. 为什么说“包 + default 访问控制”是实现模块内部协作而不暴露细节的有效方式?