美文网首页
第四十条:坚持使用Override注解

第四十条:坚持使用Override注解

作者: taogan | 来源:发表于2021-02-24 16:03 被阅读0次

java类库包含了几种注解类型。对于传统的程序员而言,这里面最重要的就是@Override注解。这个注解只能用在方法声明中,它表示被注解的方法声明覆盖了超类型中的一个方法声明。如果坚持使用这个注解,可以防止一大类的非法错误。以下面的程序为例,这里的Bigram类表示一个双字母组或者有序的字母对:

// Can you spot the bug?
public class Bigram { 
  private final char first; 
  private final char second;
  public Bigram(char first, char second) { 
    this.first = first;
    this.second = second;
  }
  public boolean equals(Bigram b) {
    return b.first == first && b.second == second; 
  }
  public int hashCode() { 
    return 31 * first + second;
  }
  public static void main(String[] args) { 
    Set<Bigram> s = new HashSet<>(); 
    for (int i = 0; i < 10; i++)
      for (char ch = 'a'; ch <= 'z'; ch++) 
        s.add(new Bigram(ch, ch));
    System.out.println(s.size()); 
  }
}

主程序反复的将26个双字母组添加到集合中,每个双字母组都由两个相同的小写字母组成。随后它打印出集合的大小。你可能以为程序打印的大小为26,因为集合不能包含重复。如果你试着运行程序,会发现它打印的不是26而是260。哪里出错了呢?

很显然,Bigram类的创建者原本想要覆盖equals方法(详见第10条),同时还记得覆盖了hashCode(详见第11章)。遗憾的是,不幸的程序员没能覆盖equals方法,而是将它重载了(详见第52条)。为了覆盖Object.equals必须定义一个参数为Object类型的equlas方法,但是Bigram类的equals方法的参数并不是Object类型,因此Bigram类从Object继承了equals方法。这个equals方法测试对象的同一性(identity),就像==操作符一样。每个bigram的10个备份中,每一个都与其余的9个不同,因此Object.equals认为它们不相等,这正是程序会打印出260的原因。

幸运的是,编译器可以帮助你发现这个错误,但是只有当你告知编译器你想要覆盖Object.equals时才发现。为了做到这一点,要用@Override标注Bigram.equals,如下所示:

@Override 
public boolean equals(Bigram b) { 
  return b.first == first && b.second == second;
}

如果插入这个注解,并试着重新编译程序,编译器就会产生如下的错误消息:

Bigram.java:10: method does not override or implement a method from a supertype

你会立即意识到哪里错了,拍拍自己的头,恍然大悟,马上用正确的来取代出错的equals实现(详见第10条):

@Override 
public boolean equals(Object o) { 
  if (!(o instanceof Bigram))
    return false;
  Bigram b = (Bigram) o;
  return b.first == first && b.second == second;
}

因此,应该在你想要覆盖超类声明的每个方法声明中使用@Override注解这一规则有个小小的例外。如果你在编写一个没有标注为抽象的类,并且确信它覆盖了超类的抽象方法,在这种情况下,就不必将Override注解放在该方法上了。在没有声明为抽象的类中,如果没有覆盖抽象的超类方法,编译器就会发出一条错误消息。但是,你可能希望关注类中所有覆盖超类方法的方法,在这种情况下,也可以放心的标注这些方法。大多数IDE可以设置为在需要覆盖的一个方法时自动插入Override注解。

大多数IDE都提供了使用Override注解的另一种理由。如果启用相应的代码检验功能,当有一个方法没有Override注解,却覆盖了超类方法时,IDE就会产生一条警告。如果使用了Override注解,这些警告就会提醒你警惕无意识的覆盖。这些警告补充了编译器的错误消息,后者会提醒你警惕无意识的覆盖失败。IDE和编译器可以确保你无一遗漏的覆盖任何你想覆盖的方法。

Override注解可以用在方法声明中,覆盖来自接口以及类的声明。由于缺省方法的出现,在接口方法的具体是线上使用Override,可以确保签名正确,这是一个很好的实践。如果知道接口没有缺省方法,可以选择省略方法的具体实现上的Override注解,以减少混乱。

但是在抽象类或者接口中,还是值得标注所有你想要的方法,来覆盖超类或者超接口方法,无论它们是具体的还是抽象的。例如,Set接口没有给Collection接口添加新方法,因此他应该在它的所有方法声明中包括Override注解,以确保它不会意外的给Collection接口添加任何新方法。

总而言之,如果在你想要的每个方法声明中使用Override注解来覆盖超类声明,编译器就可以替你防止大量的错误,但有一个例外。在具体的类中,不必标注你确信覆盖了抽象方法声明的方法(虽然这么做也没什么坏处)。

相关文章

  • 第四十条:坚持使用Override注解

    java类库包含了几种注解类型。对于传统的程序员而言,这里面最重要的就是@Override注解。这个注解只能用在方...

  • 提示四十

    提示四十:始终使用Override注解。文章先给了一个没有使用Override注解的例子,并让读者寻找问题。我看了...

  • Java注解

    本文以常用注解@Override为例,旨在描述清注解的作用与使用方法,并非详细讲解每一个注解。 @Override...

  • ITEM 40: 坚持使用 override 注解

    ITEM 40: CONSISTENTLY USE THE OVERRIDE ANNOTATION  Java库包...

  • 第36条 坚持使用Override注解

    考虑下面的程序,类Bigram 表示一个双字母组,考虑打印语句的输出结果 为什么结果是这样?bigrams采用的集...

  • 第 40 条:坚持使用Override注解

    错误示例 正确示例

  • 注解汇总

    java注解 一、标准注解 1、@Override 重写函数2、@Deprecated 不鼓励使用(有更好的方...

  • Spring注解原理探索(二)

    之 Java中如何自定义注解 1.先看注解定义示例 @Override 源码定义: 使用@interface 表示...

  • Java注解

    最近学习Retrofit,里面涉及到了注解的使用,虽然平时代码里面还是有看到很多的注解如:@Override, @...

  • Java注解

    基础注解Override WebServlet 元注解 @Target 注解的作用目标@Retention 注解的...

网友评论

      本文标题:第四十条:坚持使用Override注解

      本文链接:https://www.haomeiwen.com/subject/veesfltx.html