组成程序包的类型称为程序包成员。
要从public
包外部使用包成员,必须执行以下操作之一:
- 用其完全限定的名称引用该成员
- 导入包成员
- 导入成员的整个包
用包名来引用包成员
到目前为止,本教程中的大多数示例都通过简单名称(例如Rectangle
和StackOfInts
)来引用类型。如果您要编写的代码与该成员位于同一软件包中,或者已导入该成员,则可以使用该成员的简单名称。
但是,如果您尝试使用来自其他软件包的成员,但尚未导入该软件包,则必须使用成员的全限定名,其中包括软件包名称。这是上一个示例,在graphics
包中声明的Rectangle
类的完全限定名称。
graphics.Rectangle
您可以使用此限定名graphics.Rectangle
来创建实例:
graphics.Rectangle myRect = new graphics.Rectangle();
完全限定名称可以不经常使用。但是,当重复使用名称时,重复输入名称将变得乏味,并且代码变得难以阅读。或者,您可以导入成员或其包,然后使用其简单名称。
导入包成员
要将特定成员导入当前文件,请在任何类型定义之前,在文件的开头放置一个import
语句,但如果存在package
,则在该语句之后。这是从上一部分中创建的graphics
包中导入Rectangle
类的方式。
import graphics.Rectangle;
现在,您可以通过其简单名称Rectangle
来引用该类。
Rectangle myRectangle = new Rectangle();
如果仅使用graphics
软件包中的几个成员,则此方法效果很好。但是,如果您从包中使用许多类型,则应导入整个包。
导入整个程序包
要导入特定程序包中包含的所有类型,请使用import
带有星号(*)
通配符的语句。
import graphics.*;
现在,您可以通过其简单名称来引用graphics
包中的任何类或接口。
Circle myCircle = new Circle();
Rectangle myRectangle = new Rectangle();
import
语句中的星号只能用于指定包中的所有类,如下所示。它不能用于匹配包中类的子集。例如,以下代码与graphics
包中以A
开头的所有类都不匹配。
// does not work
import graphics.A*;
而且,它生成一个编译器错误。使用import
语句,通常只导入一个包成员或整个包。
注意: 另一种不太常见的import
形式允许您导入封闭类的公共嵌套类。例如,如果graphics.Rectangle
类包含有用的嵌套类,例如Rectangle.DoubleWide
和Rectangle.Square
,则可以使用以下两个语句来导入Rectangle
及其嵌套类。
import graphics.Rectangle;
import graphics.Rectangle.*;
请注意,第二个import语句将不会导入Rectangle
。
另一种不太常见的import
形式,静态import语句,将在本节结束讨论。
为了方便起见,Java编译器会为每个源文件自动导入两个完整的软件包:(1)java.lang
软件包和(2)当前软件包(当前文件的软件包)。
程序包的明显层次结构
最初,程序包看起来是分层的,但实际上不是。例如,Java API包括一个java.awt
包,一个java.awt.color
包,一个java.awt.font
包,以及许多其他以java.awt
开头的包。但是,java.awt.color
程序包,java.awt.font
程序包和其他java.awt.xxxx
程序包不包括在java.awt
程序包中。前缀java.awt
(Java抽象窗口工具包)用于许多相关的软件包,以使关系显而易见,但不显示包含关系。java.awt.*
导入所有在java.awt
包的类型,但它不会导入 java.awt.color
,java.awt.font
或者任何其它java.awt.xxxx
的包。如果您打算使用中java.awt
的类和其他类型,以及java.awt.color
中的类和其他类型,则必须导入两个包及其所有文件:
import java.awt.*;
import java.awt.color.*;
名字歧义
如果一个包中的成员与另一个包中的成员共享其名称,并且两个包都已导入,则必须使用其限定名称来引用每个成员。例如,graphics
程序包定义了一个名为Rectangle
的类。java.awt
软件包还包含一个Rectangle
类。如果graphics
与java.awt
已经同时导入,下面是模糊的。
Rectangle rect;
在这种情况下,您必须使用成员的全限定名来准确指示您想要的Rectangle
类。例如,
graphics.Rectangle rect;
静态导入语句
在某些情况下,您需要经常访问一两个类的静态final字段(常量)和静态方法。一遍又一遍地加上这些类的名称可能会导致代码混乱。静态导入语句(static import statement)给你一个方法,来导入常量和静态方法,这样你就不需要使用类的名称的前缀。java.lang.Math
类定义了PI
恒定和许多静态方法,包括用于计算正弦,余弦,正切,平方根,最大值,最小值,指数和更多的方法。例如,
public static final double PI
= 3.141592653589793;
public static double cos(double a)
{
...
}
通常,要使用另一个类中的这些对象,请在类名前添加前缀,如下所示。
double r = Math.cos(Math.PI * theta);
您可以使用static import语句来导入java.lang.Math的静态成员,这样就无需在类名之前添加前缀Math
。静态成员Math
可单独输入:
import static java.lang.Math.PI;
或作为一个组:
import static java.lang.Math.*;
导入静态成员后,无需限定名称,即可使用它们。例如,先前的代码片段将变为:
double r = cos(PI * theta);
显然,您可以编写自己的类,这些类包含经常使用的常量和静态方法,然后使用静态import语句。例如,
import static mypackage.MyConstants.*;
注意: 非常谨慎地使用静态导入。过度使用静态导入会导致代码难以阅读和维护,因为代码的读者不会知道哪个类定义了特定的静态对象。通过正确使用静态导入,可以消除类名重复,从而使代码更具可读性。