我刚刚看了一下TimeUnit枚举源代码(在下面简化):
public enum TimeUnit {
SECONDS {
public long toMillis(long d) { return d * 1000L; }
},
MINUTES {
public long toMillis(long d) { return d * 60000L; }
};
public long toMillis(long duration) {
throw new AbstractMethodError();
}
}
他们也可以使用一种抽象的方法来实现它:
public enum TimeUnit {
SECONDS {...}, MINUTES {...};
public abstract long toMillis(long duration);
}
既然他们选择了第一个实现,我想一定有原因。因此,我的问题是:为什么?AbstractMethodError
可以抛出吗?如果是,在哪种情况下?
标准doclet(即Sun/Oracle变体)在Javadoc输出中不提供abstract
枚举方法。如果这些方法是抽象的,Javadoc将不会显示它们的踪迹。这个错误仍然存在,最初报告于2005年(9年多前):
JDK-6287639:枚举类中的抽象方法不应列为抽象方法http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6287639
如果要实现正确的行为,这些方法将出现在Javadoc输出中,去掉抽象关键字。枚举值本质上是枚举类的匿名子类,因此javac确保枚举值实现每个抽象方法。因此,从外部观察者的角度来看,抽象枚举方法实际上是非抽象的。
以下在TimeUnit实现中编写的注释提供了更多的见解:
// To maintain full signature compatibility with 1.5, and to improve the // clarity of the generated javadoc (see 6287639: Abstract methods in // enum classes should not be listed as abstract), method convert // etc. are not declared abstract but otherwise act as abstract methods.
如果Javadoc对您的项目很重要,您可能需要考虑追随TimeUnit的脚步。
只能在其中一个枚举值未能覆盖该方法或调用超类方法时抛出异常。我不推荐那种特殊的方法;让编译器捕获这些错误要好得多,就像您建议的替代方案一样。
顺便说一句,MINUTES
的toMillis
实现在我看来肯定是错误的。这不是我在Java 7源代码中的实现。你在哪里找到的?
附言:我刚刚检查了一下:TimeUnit
的Android实现没有使用AbstractMethodError
,但也没有使用抽象方法。它使用了各种表,并在enum
级别实现了所有的转换方法。