class Groundhog2 {
  int ghNumber;
  Groundhog2(int n) { ghNumber = n; }
  public int hashCode() { return ghNumber; }
  public boolean equals(Object o) {
    return (o instanceof Groundhog2)
      && (ghNumber == ((Groundhog2)o).ghNumber);
  }
}public class SpringDetector2 {
  public static void main(String[] args) {
    Hashtable ht = new Hashtable();
    for(int i = 0; i < 10; i++)
      ht.put(new Groundhog2(i),new Prediction());
    System.out.println("ht = " + ht + "\n");
    System.out.println(
      "Looking up prediction for groundhog #3:");
    Groundhog2 gh = new Groundhog2(3);
    if(ht.containsKey(gh))
      System.out.println((Prediction)ht.get(gh));
  }
} 这是think in java上的一个例子,但是我不是很明白,
System.out.println((Prediction)ht.get(gh));
有人能把这个程序解释一下吗?

解决方案 »

  1.   

    class Groundhog2 { 
      int ghNumber;   // 属性
      Groundhog2(int n) {  // 一个带参数的构造函数,完成对属性的初始化
        ghNumber = n; 
      } 
      // 覆写hashCode方法,返回属性值(原本对象的hashCode方法是返回对象的哈希码值)  public int hashCode() {       return ghNumber; 
      } 
      /**
       *覆写equals方法
       *原来的方法是比较对象的内容是否相等,除非两个对象引用同一个对象,否则不会得到true的结。
       *覆写后,比较对象o是否是Groudhog2的实例,以及它们的属性ghNumber值是否相等,如果第一个比较不
       *成立,直接返回false(短路)。只有当两者都成立是返回true,即这两个对象内容一致。  
       */
      public boolean equals(Object o) { 
        return (o instanceof Groundhog2)&& (ghNumber == ((Groundhog2)o).ghNumber); 
      } 
    } 针对equals方法举一个简单的例子:
    class A{
       int i;
       public A() {
          i = 10;
       }
    }A a1 = new A();
    A a2 = new A();
    这时候,你输出System.out.println(a1.equals(a2));
    结果是false,虽然他们都是A的实例,虽然他们包含了同一个属性i而且值均为10。
    经过new出来的对象,会在heap内存上分配两块内存空间。只有当:
    A a1 = new A();
    A a2 = a1;
    这里会得到true。因为引用a1与a2指向heap内存上同一块空间。而这里覆写后的equals方法,不用顾及他们是否引用同一个对象,只需要满足两个条件,便可以认为这两个对象内容相等:
    它们都是Groundhog2的实例;
    它们的ghNumber相等。
      

  2.   

     
    public class SpringDetector2 {   public static void main(String[] args) { 
      // 创建哈希表
      Hashtable ht = new Hashtable();   // 哈希表内放入10个Groudhog2和Prediction对象,Groudhog2对象为键(可理解为索引),Prediction对象为值
      for(int i = 0; i  < 10; i++) 
        ht.put(new Groundhog2(i),new Prediction());   System.out.println("ht = " + ht + "\n"); 
      System.out.println("Looking up prediction for groundhog #3:");   // 创建一个Groudhog2对象gh,ghNumber属性值为2
      Groundhog2 gh = new Groundhog2(3); 
      // 测试gh对象是否为哈希表中的键,这个地方覆写equals方法的目的体现出来了
      // 如果不覆写,得到的结果将永远是false。
      // 是则,输出该键对应的Prediction对象的内容(你忘了给Prediction对象的定义,我也不知道输出什么东东)。
      if(ht.containsKey(gh)) 
        System.out.println((Prediction)ht.get(gh)); 
      } 
    }
      

  3.   


       *覆写后,比较对象o是否是Groudhog2的实例,以及它们的属性ghNumber值是否相等,如果第一个比较不 
       *成立,直接返回false(短路)。只有当两者都成立是返回true,即这两个对象内容一致。   
     
    这里解释可能有些混乱,重述一遍吧!铺垫:
    Groundhog2 gh = new Groundhog2(1);
    这个语句创建了两个对象,“引用型对象gh”和“属性ghNumber为2的Groundhog2对象”,前者在stack内存中,保存了heap内存中Groundhog2对象的首地址。你可以理解为gh指向了Groundhog2对象。关于equals方法,上面有解释。&&表示短路运算。
    a&&b
    如果a为false,则不比较b的结果,直接得到结果为false。
    如果a为true,继续看b的结果,为false,则结果false;为true,则结果true。是以谓之“短路”。
      

  4.   

    Groundhog2 gh = new Groundhog2(1); 
    这个语句创建了两个对象,“引用型对象gh”和“属性ghNumber为2的Groundhog2对象”,前者在stack内存中,保存了heap内存中Groundhog2对象的首地址。你可以理解为gh指向了Groundhog2对象。

    这段解释不是很懂,
    谢谢lisliefor!
      

  5.   

    return (o instanceof Groundhog2)&& (ghNumber == ((Groundhog2)o).ghNumber);  
    还有这句话也不懂?
    能不能稍微详细的解释下?
      

  6.   

    Groundhog2 gh = new Groundhog2(1);
    这句通常理解为“创建了一个对象”,java中的“对象”这个术语一般是指Object的实例,因此“引用”不算对象。
    gh指向堆上的一个Groundhog2对象,这是java中最基本、最常见的语句了,如果这都不能理解,建议楼主不要学java了。return (o instanceof Groundhog2)&& (ghNumber == ((Groundhog2)o).ghNumber);
    这句有点复杂,其实等价于if (o instanceof Groundhog2) {
        Groundhog2 gh = (Groundhog2)o;
        if (ghNumber == gh.ghNumber)
            return true;
        else
            return false;
    }
    else
        return false;这句利用了&&运算符的“短路”特性,即&&的左边一旦为假就返回假,不再计算右边的表达式。楼主这个例子应该是TIJ第三版第11章的,不过个人认为,如果楼主对这段程序的理解存在以上疑问,说明楼主的基础知识亟有待巩固和提高,现在就学数据结构和集合实在为时过早。
      

  7.   

    “o instanceof Groundhog2”的意思是o是否引用自Groundhog2,即对象o是否是Groundhog2的实例。是则返回true,否则返回false.
    ((Groundhog2)o)是将o强制转换成Groundhog2类型,然后比较ghNumber与o对象的ghNumber是否相等。“&&”运算为短路逻辑运算。a&&b,a、b为表达式,如果a表达式结果为false,则b就不用判断了,直接认为a&&b的结果是false,只有当a为true时,才继续判断b的结果。你看上面的例子,如果o不是Groundhog2的对象,自然不存在ghNumber属性,在不存在比较了。你网上找一下java基础面试题。一般会有这样一个问题:
    String s = new String("123");产生了几个对象?
    答案是2个,栈内存中的引用性对象s和堆内存中的字符串对象“123”,对象s保存了对象“123”的在堆内存中的内存地址。
      

  8.   

    to 楼上的Lisliefor:String s = new String("123");和Groundhog2 gh = new Groundhog2(1);是不一样的!
    前者可能产生了两个对象(注意我用的是“可能”),而后者绝对只产生了一个对象。
    你对你所说的那种面试题理解有误,那涉及的是另一个问题(String字面量的问题),要知道答案可以参看《Effective JAVA》第四条。
      

  9.   

    感谢Dan1980的提醒,我会弄透这东西的。