Effective Java

第36条 坚持使用Override注解

2017-06-27  本文已影响0人  真爱也枉然

考虑下面的程序,类Bigram 表示一个双字母组,考虑打印语句的输出结果

package thirtysix;
import java.util.HashSet;
import java.util.Set;
/**
 * Bigram
 * @author ZHAIYANMING
 * @version 1.0
 *
 */
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 bigram) {
        return bigram.first == first && bigram.second == second;
    }

    public int hashCode() {
        return 31 * first + second;
    }

    public static void main(String[] args) {
        Set<Bigram> bigrams = new HashSet<Bigram>();
        for (int i = 0; i < 10; i++) {
            for (char ch = 'a'; ch <= 'z'; ch++) {
                bigrams.add(new Bigram(ch, ch));
            }
        }
        System.out.println(bigrams.size());
    }
}

为什么结果是这样?bigrams采用的集合类型是HashSet,为什么没有去掉重复的元素呢?

/**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

HashSet的add方法的底层说明:3~5行说明了add元素e的条件:set中不存在元素e2( e==null;e2==null;e.equals(e2) )。在元素都不为null的情况下,说明这行代码e.equals(e2) 与我们想要的结果不一样.

    public boolean equals(Object obj) {
    return (this == obj);
    }

看一下Object类中的equals方法。发现代码中原本想要覆盖equals方法(发生覆盖的条件:“三同一不低”,子类和父类的方法名称,参数列表,返回类型必须完全相同,而且子类方法的访问修饰符的权限不能比父类低。),可是却重载了equals方法(发生重载的条件:方法名相同,参数列表(类型、个数、顺序)不同)。在进行这行代码( e.equals(e2) )时,就调用了Object类的equals方法,而Object类的equals方法是比较对象同一性的,即( e==e2 )。例子中:这行代码:bigrams.add(new Bigram(ch, ch)); 每次添加都会new Bigram(ch,ch),每一个Object都不一样,自然循环多少次,就add多少Object了。
随着java 1.5发行版本中增加注解,类库中也增加了几种注解类型。其中Override只能用在方法声明中,它表示被注解的方法声明覆盖了超类型中的一个声明。坚持使用这个注解,可以防止一大类非法错误。

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

如果插入这个注解,重新编译程序,编译器会产生一条错误:

The method equals(Bigram) of type Bigram must override or implement a supertype method

针对提示的错误咱们就可以修改相应的代码,这个equals方法测试对象的同一性,就像==:

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

总结:如果在你想要的每个方法声明中使用 Override 注解来覆盖超类声明 , 编译器就可以替你防止大量错误 。在具体的类中 , 不必标注你确信覆盖了抽象方法声明的方法(标注也可以)。

上一篇 下一篇

猜你喜欢

热点阅读