Effective Java(3rd)-Item40 始终使用Override注解

  Java库包含一些注解类型。对于典型的程序员来说,最重要的注解就是@Override.这个注解只能被用来方法声明,它指示了被注解的方法声明覆写了超类的声明。如果你始终使用这个注解,它将在有着恶毒的bug的类中保护你。考虑下面的这个程序,Bigram类代表了一个 双标,或订购了一对字母:

Effective Java(3rd)-Item40 始终使用Override注解_第1张图片
image.png

   主程序多次增加了二十六个双标,每个由两个相同的小写字母组成,成为了一个集合。然后打印了这个集合的大小。你可能期望程序会打印出26,因为集合不会包含重复值。如果你尝试运行这个程序,你将会发现它打印了260而不是26.哪里出现问题了?
  清楚地,Bigram类的作者指示覆写了equals方法( item10),甚至记得覆写hashCode(item11)。不幸的是,我们的程序员没有覆写equals,反而重载了它。为了覆写Object.equals,你必须定义一个equals方法,参数是Object类型,但是Bigram的equals方法不是Object类型,所以Bigram继承了Object的equals方法。这个equals方法测试对于对象标识来说,和==操作符一样。每个bigram的10个副本都不同于其他9个,因此Object.equals认为他们是不相等的,这就解释了为什么程序打印了260.

  幸运的是,编译器能帮助你找到这个错误,但是只有你通过告诉它你打算覆写Object.equals才有用。为了做到这样,给Bigram.equals带上注解@override,如下所示:


image.png

  如果你插入了这个注解,并尝试重新编译程序,编译器将生成一个错误信息如下:


Effective Java(3rd)-Item40 始终使用Override注解_第2张图片
image.png

  你将马上意识到你做错什么了。打自己的额头,并替换错误的equals实现为正确的那一个( item10 )

Effective Java(3rd)-Item40 始终使用Override注解_第3张图片
image.png

  因此,你应该 在每个方法声明中使用Override注解,只要这个方法是覆写超类声明的。这个规则有一个小例外,如果正在编写一个没有标记为抽象的类,并且你认为她覆写了它的超类中的一个抽象方法,那么你就不必在该方法上添加Override注解了。在未声明为抽象的类中,如果未能覆写抽象超类的方法,编译器将发出错误消息。但是,你可能希望注意类中覆写超类方法的所有方法,在这种情况下,你可以对这些方法进行注解。大多数的IDE可以设置自动插入Override注解,当你选择覆写一个方法。
  大多数IDE提供了另一个一致使用Override注解的另一个原因。如果你开启了合适的检查,IDE将生成一个警告,如果你有一个类没有Override注解但是它确实覆写了超类的方法。如果你一直使用Override注解,这些警告将提醒你无意中覆写。它们是对编译器的补充,这些错误消息提醒你注意无意中无法覆写的错误。在IDE和编译器之间,倪可以确保在任何地方都要覆写方法,而且没有遗漏。
  Override注解可以在那些接口上覆写声明的方法声明上的类中使用。随着默认方法的出现,在接口方法的具体实现上使用Override以确保签名是正确的是很好的做法。如果你知道接口确实没有默认方法,你可能需要在接口方法的具体实现上选择省略Override注解,减少杂乱。
  然而,在一个抽象类或在一个接口上,注解那些你认为在超类或超接口中需要覆写的方法上注解所有方法是值得的,无论是具体还是抽象方法。比如,Set接口没有向Collection接口添加新的方法,因此它应该在其所有方法声明中包含Override注解,以确保它不会意外地向Collection接口添加任何新方法。
  总之,如果你使用Override注解在每个你相信在超类声明中需要覆写的方法声明中,编译器将会保护你不会发生很多错误,但有一个例外。在具体的类中,你不需要对你认为覆写抽象方法声明的方法进行注解(虽然这么做并没有坏处)。

本文写于2019.7.9,历时2天

你可能感兴趣的:(Effective Java(3rd)-Item40 始终使用Override注解)