Java IAQ(Java最不常被回答的问题) 系列之一

问:神马是IAQ(最不常被回答的问题)?

     

一个问题不常被人回答缘由有多种,好比较少的人知道答案,或者是问题是一个不起眼的,大多数人没有注意到(但这个问题可能对你来讲是很是重要的)。咱们能够找到不少JAVA FAQs(最常被问到的问题),可是这里只有最不常被回答的问题。html

问:在finally块中的代码有没有不执行的状况?


有,这里有一个例子,在忽略choice的值的状况下,finally中的代码将不会执行。java

try {
    if (choice) {
      while (true) ;
    } else {
      System.exit(1);
    }
  } finally {
    code.to.cleanup();
  }

问:在一个类C中的方法m中,是否this.getClass()老是C。

     
  不是的,对于一些对象来讲,在C的子类C1中没有C1.m.()方法或者一些方法调用了super.m()的时候,返回的是C1。在这两种状况下,this.getClass()是C1,而不是C,除非C用final修饰了。

问:我定义了一个equals方法,可是HashTable忽略了它,为何?

    
  equals方法对于大多数人来说很难正确的使用。这里有一个例子咱们能够看看如下这些问题:
一、你定义了一个错误的equals方法,例如你这样写:
public class C {
  public boolean equals(C that) { return id(this) == id(that); }
}
     可是为了让table.get(c)正确的执行,你须要保证equals方法接收一个Object参数,而不是C
public class C {
  public boolean equals(Object that) { 
    return (that instanceof C) && id(this) == id((C)that); 
  } 
}
     为何?咱们查看HashTable的源码就知道,由于HashTable的get看起来像这样:
public class Hashtable {
  public Object get(Object key) {
    Object entry;
    ...
    if (entry.equals(key)) ...
  }
}
     如今entry.equals(key)方法调用的实际类型取决于实际运行时entry引用的对象类型。因此当你调用table.get(new C(...))的时候,他就在类C中查找带的参数为Object的equals方法。若是你恰好定义了这样一个参数为C的方法,那这个方法就可有可无了。他会忽略这个方法,寻找一个equals(Object),最终他会找到Obejct.equals(Object)方法。若是你想重写这个方法,你必须保证参数与父类的方法对应。在某些状况下你想要两个方法,这样你就不用操心你到底使用的是一个什么类型的对象了。
public class C {
  public boolean equals(Object that) {
    return (this == that) 
            || ((that instanceof C) && this.equals((C)that)); 
  }

  public boolean equals(C that) { 
    return id(this) == id(that); // Or whatever is appropriate for class C
  } 
}
二、你在实现equals方法的时候没有保证真正的相等。Equals必须具备对称性、传递性、自反性。对称性就是说a.equals(b)返回的结果必定要和b.equals(a)返回的结果相等。(这一点不少人都忽视了)。传递性,意味着若a.equals(b),b.equals(c)那么必有a.equals(c)。自反性意味着a.equals(a)必须为true。
三、你忘了hashCode方法。任什么时候候你定义一个equals方法的时候,你应该同时定义一个hashCode方法。你必须保证两个equals对象拥有相同的hashCode,若是你想让hashTable正确的运行的话,你还应该保证不相等的对象(equals返回false)拥有不相等的hashcode。一些类将hashcode缓存进了对象的一个私有的变量中,因此hashcode仅仅须要被计算一次。若是你为了节省时间而不定义hashCode方法的话,可能会致使错误。
四、你没有正确的处理继承关系。首先,考虑有没有可能两个不一样类的对象是equal的。你确定会说(不!固然不是!)如今,来看看这个例子。一个类Rectangle拥有width属性和height属性,一个Box类也有这两个属性,另外又加了一个depth属性。一个depth=0的Box等效于一个Rectangle?你可能会说是的。若是你在处理一个没有用final修饰的类的时候,你的类可能被继承,你想让你的子类使用父类C的equals方法,像这样:
public class C2 extends C {

  int newField = 0;

  public boolean equals(Object that) {
    if (this == that) return true;
    else if (!(that instanceof C2)) return false;
    else return this.newField == ((C2)that).newField && super.equals(that);
  }

}

为了使它正确执行,你必须当心若是对待equals方法。例如,检查参数是不是C的对象,要使用instanceof C而不是that.getClass()==C.class.在equals方法中使用this.getClass()==that.getClass()的时候你必须保证两个对象是同一个类型的。缓存

五、你没有正确处理循环引用。
public class LinkedList {

  Object contents;
  LinkedList next = null;

  public boolean equals(Object that) {
    return (this == that) 
      || ((that instanceof LinkedList) && this.equals((LinkedList)that)); 
  }

  public boolean equals(LinkedList that) { // Buggy!
   return Util.equals(this.contents, that.contents) &&
          Util.equals(this.next, that.next); 
  }

}
这里我假设有一个工具类:
public static boolean equals(Object x, Object y) {
    return (x == y) || (x != null && x.equals(y));
  }


若是你试图比较他们两个(相互持有引用,即形成了循环引用),LinkedList.equals方法将永远不会返回。

未完待续....

翻译水平有限,轻喷。app

OSCHINA.NET原创翻译/原文连接工具

相关文章
相关标签/搜索