當類實現接口時,接口就充當可以引用這個類的實例的類型(type)。因此類實現了接口,就表明客戶端可以對這個類的實例實施某些動作。為了其他目的而定義接口是不恰當的。
常量接口
有一種接口被稱為常量接口(constant interface),他不滿足上面的條件。這種接口沒有包含任何方法,他只包含靜態的final域,每個域都到處一個常量。使用這些常量的類實現這個接口,以避免用類名來修飾常量名。
public interface PhysicalConstants {
//阿伏伽德羅數
static final double AVOGADROS_NUMBER = 6.02214199e23;
//玻爾茲曼常數
static final double BOLRZMANN_CONSTANT = 1.3806503E-23;
//電子質量
static final double ELECTRON_MASS = 9.10938188E-31;
}
public class test implements PhysicalConstants {
public static void main(String[] args) {
Double d = 11.11;
if(d.equals(AVOGADROS_NUMBER)){
System.out.println(d);
}
}
}
阿伏伽德羅數,其具體的數值是6.0221367×1023,這個常數可用很多種不同的實驗方法進行測定。
12.000克C中所含碳原子的數目,因意大利化學家A.阿伏伽德羅而得名,具體的數值是6.0221367×10。包含阿伏伽德羅數個微粒的物質的量是 1摩爾。例如1摩爾鐵原子,質量為 55.847 克,其中含 6.0221367×10個鐵原子;1摩爾水分子的質量為18.010克,其中含6.0221367×10個水分子;1摩爾鈉離子含6.0221367×10個鈉離子;1摩爾電子含6.0221367×10個電子。
** 常量接口模式是對接口的不良使用。** 類在內部使用某些常量,這純粹是實現細節。實現常量接口,會導致把這樣的實現細節泄露到該類的導出API中。類實現常量接口,這對于用戶來講并沒有什么價值。實際上,這樣做反而會使他們更加糊涂。更糟糕的是,他代表了一種承諾:如果將來的發行版本中,這個類被修改了,他不再需要使用這些常量了,他依然必須實現這個接口,以確保二進制兼容性。如果非final類實現了常亮接口,他的所有子類的命名空間也會被接口中的常量所“污染”。
在java平臺類庫中有幾個常量接口,例如java.io.ObjectStreamConstants。這些接口應該被認為是反面的典型,不值得被效仿。
package java.io;
/**
* Constants written into the Object Serialization Stream.
*
* @author unascribed
* @since JDK 1.1
*/
public interface ObjectStreamConstants {
/**
* Magic number that is written to the stream header.
*/
final static short STREAM_MAGIC = (short)0xaced;
/**
* Version number that is written to the stream header.
*/
final static short STREAM_VERSION = 5;
/* Each item in the stream is preceded by a tag
*/
/**
* First tag value.
*/
final static byte TC_BASE = 0x70;
public class ObjectInputStream
extends InputStream implements ObjectInput, ObjectStreamConstants
{
/** handle value representing null */
private static final int NULL_HANDLE = -1;
/** marker for unshared objects in internal handle table */
private static final Object unsharedMarker = new Object();
/** table mapping primitive type names to corresponding class objects */
private static final HashMap<String, Class<?>> primClasses
= new HashMap<>(8, 1.0F);
(省略若干行)
/**
* The readStreamHeader method is provided to allow subclasses to read and
* verify their own stream headers. It reads and verifies the magic number
* and version number.
*
* @throws IOException if there are I/O errors while reading from the
* underlying <code>InputStream</code>
* @throws StreamCorruptedException if control information in the stream
* is inconsistent
*/
protected void readStreamHeader()
throws IOException, StreamCorruptedException
{
short s0 = bin.readShort();
short s1 = bin.readShort();
if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
throw new StreamCorruptedException(
String.format("invalid stream header: %04X%04X", s0, s1));
}
}
如果要導出常量,可以有幾種合理的選擇方案。
- 如果這些常量與某個現有的類或者接口緊密相關,就應該把這些常量添加到這個類或者接口中。例如,在java平臺類庫中所有的數值包裝類,比如Integer和Double,都導出了MIN_VALUE和MAX_VALUE常量。
public final class Integer extends Number implements Comparable<Integer> {
/**
* A constant holding the minimum value an <code>int</code> can
* have, -2<sup>31</sup>.
*/
public static final int MIN_VALUE = 0x80000000;
/**
* A constant holding the maximum value an <code>int</code> can
* have, 2<sup>31</sup>-1.
*/
public static final int MAX_VALUE = 0x7fffffff;
- 如果這些常量最好被看做枚舉類型的成員,就應該用枚舉類型(enum type)(見30條)來導出這些常量。
- 使用不可實例化的工具類(utility class)(見4條)來導出這些常量
public class PhysicalConstants {
private PhysicalConstants(){}
//阿伏伽德羅數
public static final double AVOGADROS_NUMBER = 6.02214199e23;
//玻爾茲曼常數
public static final double BOLRZMANN_CONSTANT = 1.3806503E-23;
//電子質量
public static final double ELECTRON_MASS = 9.10938188E-31;
}
工具類通常要求客戶端要用類名來修飾這些常量名,例如PhysicalConstants.AVOGADROS_NUMBER。如果大量利用工具類導出的常量,可以通過利用靜態導入(static import)機制。避免用類名來修飾常量名,不過靜態導入機制是在java發行版本1.5中才引入的:
package example;
import static example.PhysicalConstants.*;
/**
* Created by Jiang Meiwei on 2017/5/7.
*/
public class test {
double atoms(double mols){
return AVOGADROS_NUMBER * mols;
}
}
總結:
簡而言之,接口應該只被用來定義類型,他不應該被用來導出常量。