Java 中的包

2025年4月21日 | 阅读 10 分钟

Java 包是相似类型的类、接口和子包的集合。

包示例

示例

立即执行

输出

Welcome to the package

使用以下命令编译并运行上述程序。

javac -d . Main.java

为什么使用包?

避免命名冲突:包用于避免类名之间的命名冲突。

假设有一个名为 Employee 的类。我们知道公司中员工在 HR 和 IT 部门。所以,问题是,如果我们写 Employee,那么它是属于哪个部门的?这里,包就派上用场了,我们可以将 Employee 写成完全限定名,分别代表两个部门和company.hr.Employeecompany.it.Employee。这样,就避免了命名冲突。

组织类:包用于组织类、接口和其他组件。

想象一个图书馆。不同类型的书籍有不同的书架。数学书放在一个地方。科学书放在另一个地方,等等。同样,我们也可以将相似类型的类分组放在一个地方。包有助于做到这一点。在 Java 中,内置类也是使用包来组织的。观察下图。

Packages in Java
  • 控制访问:包控制受保护和默认成员的访问。试想一下,如果没有包,默认和受保护的访问说明符还有什么用?
  • 可重用性:Java 通过包增强了代码的可重用性管理,并促进了数据封装。

Java 包的工作原理

命名约定:Java 包应小写,组件应使用点 (.) 分隔。如果组件是一个类,则类名的首字母应大写。

要阅读更多 Java 命名约定

目录结构:目录名称和包名称密切相关。

例如,如果包名是company.hr.Employee,则 company 是目录,其中有一个名为 hr 的目录,其中有一个名为 Employee 的类。请注意,E 是大写的,表示这是一个类名。

示例

这里,langjava 包中的一个子包。

访问类

导入特定类

我们可以使用 import 关键字访问包中的类。例如,如果我们想访问 java.util 包中的特定类,则使用以下语句

在这里,我们正在访问 java.util 包中一个名为 ArrayList 的特定类。同样,如果我们想包含另一个包中的另一个类,我们可以写

在这里,我们导入了 java.math 包中的 BigInteger 类。

导入所有类

如果我们想在不使用 import 语句的情况下使用一个类,那么我们必须写如下内容。

示例

编译并运行

输出

Inside the main method

注意:通过应用 import package.*; 语句,我们知道它导入了该包中存在的所有类和接口。但是,所有类、接口等都不会从它们的子包中导入。

当我们在两个具有同名类(例如,java.sql.Datejava.util.Date)的包时,建议使用完全限定名来避免名称冲突。我们将在本教程的后面部分看到这一点。

包的类型

Java 中有两种类型的包。

  1. 内置包
  2. 用户定义的包

内置包

一些常用的内置包是

java.lang: 它包含语言支持所需的类,例如基本数据类型和数学运算的类。此包会自动导入到 Java 中。

java.io: 它包含输入/输出操作所需的所有类。

java.util: 它包含数据结构所需的实用类,例如 ArrayListMap 等。

java.applet: 查找 applet 所需的所有类都在此包中。

java.awt: 它包含创建 GUI(图形用户界面)组件所需的所有类。

java.net: 它包括用于执行网络领域任务的类。

用户定义的包

在本节中,我们将在两个不同的包(或文件夹)中创建两个 Java 文件。我们还将创建三个文件。每个文件夹一个文件,最后一个文件是主类。

观察以下内容。已创建 mypackage1 和 mypackage2 两个文件夹。

Packages in Java

在 mypackage1 中,创建一个文件 Class1.java。

Packages in Java

为 Class1.java 文件编写以下代码。

同样,在 mypackage2 中创建 Class2.java 文件

Packages in Java

为 Class2.java 文件编写以下代码。

现在,在这两个包的外部,创建 Main.java 文件。

Packages in Java

为 Main.java 文件编写以下代码。

示例

输出

Inside the package 1.
Inside the package 2.

注意:如果我们把 Class1 和 Class2 的访问说明符从 public 改为 protected、default 或 private,编译器将报错。观察以下内容。

将此文件保存为 Class1.java

将此文件保存为 Class2.java

现在,当我们运行 Main.java 文件时,会观察到以下错误。

.\mypackage1\Class1.java:3: error: modifier protected not allowed here
protected class Class1 { // changed the access specifier to protected
          ^
Main.java:2: error: Class1 is not public in mypackage1; cannot be accessed from outside package
import mypackage1.Class1;
                 ^
Main.java:4: error: Class2 is not public in mypackage2; cannot be accessed from outside package
import myPackage2.Class2;
                 ^
Main.java:11: error: Class1 is not public in mypackage1; cannot be accessed from outside package
        Class1 obj1 = new Class1();
        ^
Main.java:11: error: Class1 is not public in mypackage1; cannot be accessed from outside package
        Class1 obj1 = new Class1();
                          ^
Main.java:13: error: Class2 is not public in mypackage2; cannot be accessed from outside package
                Class2 obj2 = new Class2();
                ^
Main.java:13: error: Class2 is not public in mypackage2; cannot be accessed from outside package
                Class2 obj2 = new Class2();

说明

错误发生的原因是 protected 和 default 访问说明符限制了类在包外的可见性。因此,主类无法访问 Class1 和 Class2。

注意:在此示例中,我们显式创建了 mypackage1 和 mypackage2 文件夹。如果想通过命令提示符构建,请执行以下操作。

首先,将所有三个文件(Class1.java、Class2.java、Main.java)放在一个位置(我的例子中是 test 文件夹)。

Packages in Java

在这种情况下,确保 Class1 和 Class2 的访问说明符为 public。现在,使用以下命令进行编译。

这里,-d 表示目标。在 -d 之后,我们看到一个点 (.),表示当前目录,*.java 表示所有 Java 文件。

完成编译工作后,我们看到以下内容。

Packages in Java

我们看到两个包都已创建。现在,使用命令运行 Main.class 文件

我们得到输出:

Inside the package 1.
Inside the package 2.

静态导入

静态导入功能首次引入于 Java 5 版本,并且在后续的 Java 版本中仍然存在。静态导入允许在代码中使用类的 **public static 成员**(方法或字段),而无需指定定义它的类的名称。

要阅读更多 Java 静态导入

示例

输出

In the main method

说明

"System" 是 java.lang 包中的一个类,out 是 System 类中的一个静态变量。通过使用静态导入,我们可以访问 out 变量而不使用 "System" 类名。

处理名称冲突

如前所述,可以使用包来处理名称冲突。让我们看一个示例来理解这一点。

示例

输出

Main.java:7: error: reference to Date is ambiguous
       Date d = new Date(44l);
       ^
  both class java.util.Date in java.util and class java.sql.Date in java.sql match
Main.java:7: error: reference to Date is ambiguous
       Date d = new Date(44l);
                    ^
  both class java.util.Date in java.util and class java.sql.Date in java.sql match
2 errors

说明

在程序中,导入了 java.sql 和 java.util 包。每个包都包含 Date 类。当实例化 Date 类时,编译器不知道它应该引用哪个 Date 类,是 java.sql 包中的 Date 类还是 java.util 包中的 Date 类。这会导致歧义。因此,出现了错误。

为了解决这个错误,我们必须使用类名以及包名。完全限定名清楚地告诉编译器它应该引用哪个 Date 类。

示例

输出

Inside the main method.

Java 中的子包

包里面的包称为子包。它应该被创建以进一步对包进行分类

让我们举一个例子,Sun Microsystems 定义了一个名为 java 的包,其中包含许多类,如 SystemStringReaderWriterSocket 等。这些类代表一个特定的组。例如,Reader 和 Writer 类用于输入/输出操作,Socket 和 ServerSocket 类用于网络,等等。

因此,Sun 将 Java 包子分类为 lang、net、io 等子包,并将输入/输出相关的类放在 io 包中,将 Server 和 ServerSocket 类放在 net 包中,等等。

定义包的标准是 domain.company.package,例如 com.tpointtech.bean 或 org.sssit.dao。

子包示例

示例

编译:javac -d . Main.java

运行:java com.tpointtech.core.Main

输出

Hello subpackage

Java 5 的静态导入功能是什么?

点击 Java 5 的静态导入功能。

关于包类怎么样?

点击 包类


Java 包选择题

1. 以下关于 Java 包的说法哪个是正确的?

  1. 包是类和接口的集合。
  2. Java 中的包只能包含类,不能包含接口。
  3. 包通过提供命名空间来帮助解决命名冲突。
  4. A 和 C 均正确。
 

答案:D

解释:在 Java 中,包是一个命名空间,可以包含类、接口、枚举和注解。包有助于组织代码并通过提供命名空间来解决命名冲突。


2. 要导入名为 myPackage 的包中的所有类的正确方法是什么?

  1. import myPackage;
  2. import myPackage.*;
  3. import myPackage.All;
  4. import myPackage.allClasses;
 

答案:B

解释:导入包中所有类的正确语法是 import myPackage.*;。该语句导入 myPackage 中所有公共类和接口。


3. 以下关于 java.lang 包的说法哪个是正确的?

  1. 它必须在每个 Java 程序中显式导入。
  2. 它包含 String 和 System 等基本类。
  3. 它不包含在默认导入列表中。
  4. 它在 Java 8 及更高版本中已弃用。
 

答案:B

解释:java.lang 包包含对 Java 编程至关重要的基本类,例如 String、System、Math、Thread 等。该包默认隐式导入,因此无需显式导入。


4. Java 编译器 (javac) 如何处理 Java 源文件中的包语句?

  1. 如果包语句后面没有 import 语句,则该语句将被忽略。
  2. 包语句必须是源文件中的第一条语句,排除注释和空格。
  3. 包语句是可选的,可以在源文件中的任何位置出现。
  4. 包语句必须紧跟类定义。
 

答案:B

解释:在 Java 源文件中,如果存在包语句,则它必须是第一条语句(排除注释和空格)。它定义了该类所属的包。


5. package-info.java 文件的主要目的是什么?

  1. 定义包的主类。
  2. 提供包级别的文档和注解。
  3. 导入其他包中的类。
  4. 包含包的元数据,如版本和作者信息。
 

答案:B

解释:package-info.java 文件用于提供包级别的文档和注解。该文件包含一个包声明,后跟 Javadoc 注释和注解。它不包含类定义或导入。它主要用于记录整个包并对包应用注解。