Effective-Java-40坚持使用Override注解
Java 类库中包含了几种注解类型。一般来说,其中最重要的是 @Override 注解。该注解仅能用于方法声明,表示被注解的方法声明覆盖了超类中的一个方法声明。坚持使用该注解,可以防止一大类的非法错误。[1]请看代码段
1 | /** |
该程序将反复的把 26 个双字母组合添加进集合中 (每个字母组合都由两个相同的小写字母组成),随后打印该集合的大小。结果见注释,期望的结果是 26 ,因为存在重复添加相同字母组合的情况。[2]
显然 Bigram 类的创建者原本想覆盖 equals 方法(见第10条),同时还记得覆盖 hashCode。实际上 equals 没有被重写,而是被重载了。[3]重写 Object.equals 必须定义一个参数为 Object 类型的 equals 方法,但Bigram 类中定义的是 Bigram 类型,因此 Bigram 类从Object 类继承了equals ,该 equals 比较对象的同一性 (identity),就像 == 操作符一样。[4]所以对于每一个 bigram 的重复添加,都被看做是不同的,这就是结果为 260 的原因。[5]
幸运的是,编译器可以可以帮助你发现这个错误,但是需要告知编译器想要重写 Object.equals才行。用 @Override 标注Bigram.equals,如下[6]
1 | /** |
如果插入这个注解,会发现错误信息。将其改正为:
1 |
|
因此,应在想要重写超类声明的每个方法中使用 Override 注解。[7]
Oracle Java SE 21 API,
java.lang.Override, defines@Overrideas a method-declaration annotation and specifies the compiler error condition when the annotated method does not override, implement, or match anObjectpublic method. ↩︎Joshua Bloch, Effective Java, 3rd Edition, Item 40, uses the Bigram example to motivate consistent use of
@Override. ↩︎Java Language Specification SE 21, §8.4.2 Method Signature and §8.4.8.1 Overriding, distinguish methods by name and parameter types and define when an instance method overrides another. ↩︎
Oracle Java SE 21 API,
Object.equals(Object), documents that the default implementation uses reference equality, equivalent to==for non-null references. ↩︎Oracle Java SE 21 API,
HashSet, documents a hash-table-backedSet; together withObject.equals(Object)andObject.hashCode(), this supports why distinct Bigram instances remain distinct whenequals(Object)is not actually overridden. ↩︎Oracle Java SE 21 API,
java.lang.Override, requires compilers to report an error when an annotated method does not meet one of the permitted override/implementation conditions. ↩︎Effective Java Item 40 gives the practice rule to use
@Overrideconsistently; Error Prone,MissingOverride, shows the same rule encoded as a static-analysis check. ↩︎