Java静态导入实际上就是通过给导入包名中添加一个static关键字,从而直接通过方法名使用方法。这样的好处是无须使用类名调用,或者新建一个对象来调用其中的方法。静态导入需要在一定的条件下才能进行,它要求对象中所有方法都是静态方法。
事实上,在《有效的Java》一书中Joshua Bloch提到Java开发人员应仅使用接口声明类型。我们不应该使用接口来声明常量接口,它们是仅用于导出常量的接口。下面的Switchable常量接口提供了一个示例。
public interface Switchable
{
boolean OFF = false;
boolean ON = true;
}
开发人员可以使用常量接口来避免必须在常量名称之前添加其引用类型的名称(例如Math.PI)。例如,下面代码中的Light类,该类实现了Switchable接口,以便开发人员可以自由地指定常量OFF,ON而不必包括类前缀(如果它们在类中声明的话)。
public class Light implements Switchable
{
private boolean state = OFF;
public void printState()
{
System.out.printf("state = %s%n", (state == OFF) ? "OFF" : "ON");
}
public void toggle()
{
state = (state == OFF) ? ON : OFF;
}
}
常量接口提供旨在用于类的实现中的常量。作为实现的详细信息,我们不应将常量泄漏到类的导出的API中,因为它们可能会使使用我们的类的其他类感到困惑。此外,为了保持二进制的兼容性,即使我们不再使用该类,也应致力于支持它们的发展。
为了满足对常量接口的需求,同时避免了使用它们带来的问题,Java 5引入了静态导入。此语言功能可用于导入引用类型的静态成员。它是通过以下import static语句实现的:
import static packagespec . typename . ( staticmembername | * );
static在之后放置import将此语句与常规import语句区分开。import就包和子包名称的标准句点分隔列表而言,该语法与常规语句相似。你可以导入单个静态成员名称或所有静态成员名称。
import static java.lang.Math.*; // Import all static members from Math.
import static java.lang.Math.PI; // Import the PI static constant only.
import static java.lang.Math.cos; // Import the cos() static method only.
通过上面的例子我们发现,在导入它们之后,你可以指定静态成员,而不必在其类型名称前添加前缀,大大提高了代码的简洁度。例如,在指定第一个或第三个静态导入后,你可以cos直接指定,如
double
cosine = cos(angle);
为了修复Switchable接口,使其不再依赖implements Switchable,我们可以插入静态导入,如下列代码所示。
静态导入改进了Switchable的实现
package foo;
import static foo.Switchable.*;
public class Light
{
private boolean state = OFF;
public void printState()
{
System.out.printf("state = %s%n", (state == OFF) ? "OFF" : "ON");
}
public void toggle()
{
state = (state == OFF) ? ON : OFF;
}
}
该程序代码以一条package foo;语句开头,因为你不能从未命名包中的类型导入静态成员。该程序包名称显示为后续静态导入的一部分:
import static
foo.Switchable.*;
在使用静态导入时,我们还要注意以下两点:
首先,当两个静态导入导入同名成员时,编译器将报告错误。例如,假设包physics包含一个Math与java.lang的Math类相同的类,因为它实现了相同的PI常量和三角函数方法。当由下面的代码片断面对,编译器报告错误,因为它不能确定是否java.lang.Math的或physics.Math的PI恒定正被访问和cos()方法被调用:
import static java.lang.Math.cos;
import static physics.Math.cos;
double angle = PI;
System.out.println(cos(angle));
其次,过度使用静态导入会破坏导入的所有静态成员的代码名称空间,这会使代码难以读取和不可维护。另外,任何阅读代码的人都可能很难找出静态成员来自哪种类型,尤其是从类型中导入所有静态成员名称时。
其实我们不难发现,java中的静态导入技术是一把双刃剑,用好了可以极大地提高代码的效率,无需使用类名或者新建对象,同时用错了也会导致编译器报错。手握利刃,我们应存着敬畏之心,我们可以在本站学习更多关于静态导入的专业课程,让我们有能力去使利刃归鞘。