当类实现接口时,接口就充当可以引用这个类的实例的类型。因此,类实现了接口,就表明客户端对这个类的实例可以实施某些动作。为了任何其他目的而定义的接口是不恰当的。
有一种接口被称为常量接口(constant interface),这种接口没有包含任何方法,它只包含静态的final域,每个域都导出一个常量。下面是一个例子
public interface PhysicalConstants {
static final double AVOGADROS_NUMBER = 6.23156412e23; //阿伏伽德罗数
static final double BOLTZMANN_CONSTANT = 1.12588456e-23; //玻尔兹曼常数
static final double ELECTRON_MASS = 9.10938188e-31; //电子质量
}
常量接口模式是对接口的不良使用。类在内部使用某些常量,纯粹是实现细节,实现常量接口,会导致把这样的实现细节泄露到该类的导出API中,因为接口中所有的域及方法都是public的。类实现常量接口,代表了一种承诺:如果在将来的发行版本中,这个类被修改了,它不再需要使用这些常量了,依然必须实现这个接口,以确保二进制兼容性。如果非final类实现了常量接口,它的所有子类的命名空间都受到了污染。
那既然不适合存在全部都是导出常量的常量接口,那么如果需要导出常量,它们应该放在哪里呢?
1.如果这些常量与某些现有的类或者接口紧密相关,就应该把这些常量添加到这个类或者接口中(如Integer和Double),注意,这里说添加到接口中并不是指的常量接口。在Java平台类库中所有的数值包装类都导出MIN_VALUE和MAX_VALUE常量。如果这些常量最好被看作是枚举类型成员,那就应该用枚举类型来导出。
如:int类型的取值范围是多少?
这就应该去查 Integer -- Integer.MAX_VALUE;
public enum PhysicalConstants {
AVOGADROS_NUMBER(6.23156412e23),BOLTZMANN_CONSTANT(1.12588456e-23),ELECTRON_MASS(9.10938188e-31);
private final Double constant;
PhysicalConstants(Double number) {
thie.constant = number;
}
public Double constant() {
return constant;
}
}
2.应该使用不可实例化的工具类来导出这些常量。
public class PhysicalConstants {
private PhysicalConstants() {}
public static final double AVOGADROS_NUMBER = 6.23156412e23;
public static final double BOLTZMANN_CONSTANT = 1.12588456e-23;
...
}
工具类通常要求客户端要用类名来修饰这些常量名。例如PhysicalConstants.AVOGADROS_NUMBER。如果大量利用工具类导出的常量,那么可以通过静态导入(static import)机制来避免用类名来修饰常量名。静态导入的作用是把PhysicalConstants类中的AVOGADROS_NUMBER 、BOLTZMANN_CONSTANT 等常量引入到本类中,这会使程序更简单,更容易阅读,只要看到AVOGADROS_NUMBER就知道这是阿伏伽德罗常数,不用每次都要把类名写全了。但是,滥用静态导入会使程序更难阅读,更难维护。
// Use of static import to avoid qualifying constants
import static effectivejava.PhysicalConstants.*;
public class Test {
double atoms(double mols) {
return AVOGADROS_NUMBER * mols;
}
...
// Many more uses of PhysicalConstants justify static import
}
PS:在Java程序中,是不允许定义独立的函数和常量(准确的说,只是被final修饰、只能赋值一次的变量)的。即使从它们本身的功能来看,完全不需要依附于什么东西,也要找个类或接口作为挂靠单位才行(在类里可以挂靠各种成员,而接口里则只能挂靠常量)。
挂靠的方法,是把它们加上static修饰符,定义为这个类或接口的静态成员。这方面的典型例子是java.lang.Math类——包含了大量的sin、cos这样的“函数”和PI、E这样的“常量”。
传统上,在访问这些挂靠了的函数、变量和常量的时候,需要在前面加上它们挂靠单位的名称。如果只是偶尔访问这些东西一下,这样的写法可以工作得很好;但是如果要频繁访问这些成员的话,这样的写法就显得比较罗嗦了。
简而言之,接口应该只用来定义类型,它不应该被用来导出常量。