原文链接
文章也上传到
(欢迎关注,欢迎大神提点。)
Item 22 仅仅使用接口来定义类型
当一个类实现了一个接口时,这个接口就被当作一个可以引用该类对象的类型在使用。因此类实现了哪个接口,就能调用哪个接口的方法。
用接口类定义其他事情都是不恰当。
有一种失败的接口是常量接口。这样的接口没有包含任何方法,仅仅包含一些static final的常量。这里有个例子:
//常量接口反例-不要这样用
public interface PhysicalConstants {
// Avogadro's number (1/mol)
static final double AVOGADROS_NUMBER =
6.022_140_857e23;
// Boltzmann constant (J/K)
static final double BOLTZMANN_CONSTANT =
1.380_648_52e-23;
// Mass of the electron (kg)
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
这个常量接口是对接口的不良用法。类使用的什么常量属于内部的实现细节。但是当类实现一个常量接口时,就会导致类的内部实现细节被暴漏到类导出的API中。对用户来说,类实现常量接口不但用处不大而且容易造成混乱。更糟糕的是,常量接口代表了一个承诺:如果将来类被修改成不再需要使用这些常量,但它为了二进制兼容还必须继续实现这个接口,这很痛苦。如果一个非final的类实现了常量接口,那么它子类的命名空间就可能被这些常量污染。
在JAVA平台库中有几个常量接口存在,例如java.io.ObjectStreamConstants.这些接口应该被视为不规则的不应该被效仿的接口。
如果你想导出常量,有几种合理的选择。
- 如果常量与现有的类或者接口强关联,那么你应该把他们添加到这个类和接口上。例如,所有的原始数值包装类中,像Integer和Double,都导出了MIN_VALUE和MAX_VALUE常量。
- 如果常量是被当作枚举使用的,那么你就应该把常量导出成一个enum类型(Item34)。
- 否则,你应该导出一个不可实例化的工具类包含这些常量(Item4)。例如前面的例子:
package com.effectivejava.science;
public class PhysicalConstants {
private PhysicalConstants() { } // Prevents instantiation
public static final double AVOGADROS_NUMBER =
6.022_140_857e23;
public static final double BOLTZMANN_CONST =
1.380_648_52e-23;
public static final double ELECTRON_MASS =
9.109_383_56e-31;
}
顺便说一下,注意在上面的数字中使用的下划线(_),从Java7开始是合法的使用,添加下划线不会影响数字的值,而且能使数字的可读性更强。无论是整数还是小数,当数字个数超过5个的时候,你都可以每3个分成一组来划分。
通常使用工具类调用常量时要求用类名.常量名,例如PhysicalConstants.AVOGADROS_NUMBER.但是如果你大量的使用常量时,可以通过导入工具类来直接使用常量:
import static com.effectivejava.science.PhysicalConstants.*;
public class Test {
double atoms(double mols) {
return AVOGADROS_NUMBER * mols;
}
...
// Many more uses of PhysicalConstants justify static import
}
总结:接口应该仅被用于定义类型,而不应该用于仅仅导出常量。