有这样一道考题:Given:
2. class Chilis {
3. Chilis(String c, int h) { color = c; hotness = h; }
4. String color;
5. int hotness;
6. public boolean equals(Object o) {
7. if(this == (Chilis)o) return true;
8. return false;
9. }
10. public String toString() { return color + " " + hotness; }
11. }If instances of class Chilis are to be used as keys in a Map, which are true? (Choose all that
apply.)
A. Without overriding hashCode(), the code will not compile.
B. As it stands, the equals() method has been legally overridden.
C. It’s possible for such keys to find the correct entries in the Map.
D. It’s NOT possible for such keys to find the correct entries in the Map.
E. As it stands, the Chilis class legally supports the equals() and hashCode() contracts.
F. If hashCode() was correctly overridden, it would make retrieving Map entries by key easier.正确答案是:B C E它为什么不选F呢?首先它没有重写hashCode(),我以为重写hashcode()会提高搜索速度,相当于给对象加了个主键,只按主键搜索,而不是一个一个对象去搜索,不是这样么?请高手指点迷津
而且equals()的重写也没有起到真正的作用,只要2个Chillis对象比较,统统返回true。hashcodescjpmap

解决方案 »

  1.   

    将模拟代码上传,请高手点评:
    另外,我上面最后一句话说错了,它的equals相当于没有重写,==,实际上比较的还是object的equals(),只有两个引用完全指向同一对象时,才返回true。我还是不知道重写hashcode(),是不是会提高搜索速度?请高手指教package com.ocjp.mapKeyedByObj;import java.util.HashMap;
    import java.util.Map;public class MapKeyedByObj {
    String name;

    public MapKeyedByObj(String name) {
    super();
    this.name = name;
    } public static void main(String[] args) {

    Map<Chilis,String> map = new HashMap<Chilis,String>();
    MapKeyedByObj m1 = new MapKeyedByObj("zs");
    MapKeyedByObj m2 = new MapKeyedByObj("ls");
    Chilis c1 = new Chilis("red",100);
    // Chilis c2 = new Chilis("blue",200);
    map.put(c1, m1.name);
    map.put(new Chilis("blue",200), m2.name);
    System.out.println(map.get(c1));
    System.out.println(map.get(new Chilis("blue",200)));
    // System.out.println(map.get(new Chilis("yellow",300)));
    System.out.println(c1.equals(c1));
    System.out.println(new Chilis("blue",200).equals(new Chilis("blue",200)));
    }
    }class Chilis {
    Chilis(String c, int h) { color = c; hotness = h; }
    String color;
    int hotness;
    public boolean equals(Object o) {
    if(this == (Chilis)o) return true;
    return false;
    }
    public String toString() { return color + " " + hotness; }
    }
      

  2.   

    翻译F选项:
    如果合理地重写hashcode()方法,按key(Chilis对象)搜索map entry可以变得更容易一些
      

  3.   

    你如果不重写hashcode()
    java还是会调用自带的hashcode()吧,其原理一样是把字符串定位到某个物理地址上,
    而你如果重写的话,效果应该是一样的。
      

  4.   

    http://www.jusfortechies.com/java/core-java/hashcode.php
      

  5.   

    搜索是先根据hashcode()去创建index如果2个对象的hashcode()相等,再去比较equals(),两个方法都返回true,才能拿到map key,这也就是F选项中所说的map entry
      

  6.   

    重写equals(),必须重写hashcode(),而且它俩必须结果一致。
    即equals()的两个对象,hashcode()必须相等,否则,没用
      

  7.   


    学习了,大多数时候hashcode都是调用父类的,而equals大部分时候都是覆写的。
      

  8.   

     仅仅对于HashSet、HashMap之类的哈希表,“equals()的两个对象,hashcode()必须相等,否则,没用”是正确的。
      JDK的所有哈希表均采用拉链法解决哈希冲突,当你调用put()方法的时候,JDK会先算出对象的hashcode(),如果此hashcode对应的链表为空,则会直接插入;否则将遍历整个链表,依次调用已经存在的元素的equals()进行比较;如果equals()==true,则不插入,break;当遍历完整个链表之后,说明这个链表所有对象的equals()==false,把新的对象插入到链表头部。
      如果想使用JDK的哈希表,一般无需重写hashcode,因为Object自带的hashcode做的很好,在数据量不大的情况下,不会有任何冲突,CRUD的复杂度均为O(1)。
      但当数据量非常大时,如:超过千万级,对象的hashcode难免会出现重复;如果数据量更大,则冲突会更加严重,哈希表的CRUD效率将逐渐退化为O(sqrt(N))。此时,你就可以重写hashcode来减少冲突。或者重写compareTo方法,使用TreeMap,对于超大数据量,TreeMap的效率是O(log2N),反而好于HashMap。
      另外,最重要的,不要只从“重写”、“继承”等等肤浅的角度去分析问题,也不要轻信别人的回复(包括我的回复)、甚至ThinkingInJava、Java核心技术的相关解释之后,就把问题丢在一边;调试和分析JDK源码,才是掌握知识的最权威、最直接的方式!
      

  9.   

    上传有点实际价值的代码,下面的代码,可以找到相同的对象,并可也从MAP中提取keypackage com.ocjp.mapKeyedByObj;import java.util.HashMap;
    import java.util.Map;public class MapKeyedByObj {
    String name;

    public MapKeyedByObj(String name) {
    super();
    this.name = name;
    } public static void main(String[] args) {

    Map<Chilis,String> map = new HashMap<Chilis,String>();
    MapKeyedByObj m1 = new MapKeyedByObj("zs");
    MapKeyedByObj m2 = new MapKeyedByObj("ls");
    Chilis c1 = new Chilis("red",100);
    Chilis c2 = new Chilis("red",200);
    map.put(c1, m1.name);
    // map.put(c2, m2.name); //加上这句话后,map.get(c1)将变成,键值c2==c1,m2.name将m1.name覆盖了
    map.put(new Chilis("blue",200), m2.name);
    System.out.println(map.get(c1));
    System.out.println(map.get(new Chilis("blue",200)));
    // System.out.println(map.get(new Chilis("yellow",300)));
    System.out.println(c1.equals(c2)); //根据重写后的hashcode(), equqls();output: true
    System.out.println(new Chilis("blue",200).equals(new Chilis("blue",200))); //根据重写后的hashcode(), equqls();output:true
    System.out.println(c1.hashCode());
    System.out.println(c2.hashCode());
    }
    }class Chilis {
    Chilis(String c, int h) { color = c; hotness = h; }
    String color;
    int hotness;

    //只有2个对象完全==,即指地址相同时,才返回true.这样重写hashcode(),也不会找到两个完全相同的对象。
    //只有2个对象引用到同一块同存时,才相等,即c1==c1;
    // @Override
    // public boolean equals(Object o) {
    // if(this == (Chilis)o) return true; 
    // return false;
    // } @Override
    public boolean equals(Object o) {
    if(!(o instanceof Chilis)){
    return false;
    }else{
    Chilis c = (Chilis)o;
    if(this.color==c.color){
    return true;
    }
    }
    return false;
    }



    @Override
    public int hashCode(){
    return this.color.hashCode();
    }

    public String toString() { return color + " " + hotness; }
    }
      

  10.   

     仅仅对于HashSet、HashMap之类的哈希表,“equals()的两个对象,hashcode()必须相等,否则,没用”是正确的。
      JDK的所有哈希表均采用拉链法解决哈希冲突,当你调用put()方法的时候,JDK会先算出对象的hashcode(),如果此hashcode对应的链表为空,则会直接插入;否则将遍历整个链表,依次调用已经存在的元素的equals()进行比较;如果equals()==true,则不插入,break;当遍历完整个链表之后,说明这个链表所有对象的equals()==false,把新的对象插入到链表头部。
      如果想使用JDK的哈希表,一般无需重写hashcode,因为Object自带的hashcode做的很好,在数据量不大的情况下,不会有任何冲突,CRUD的复杂度均为O(1)。
      但当数据量非常大时,如:超过千万级,对象的hashcode难免会出现重复;如果数据量更大,则冲突会更加严重,哈希表的CRUD效率将逐渐退化为O(sqrt(N))。此时,你就可以重写hashcode来减少冲突。或者重写compareTo方法,使用TreeMap,对于超大数据量,TreeMap的效率是O(log2N),反而好于HashMap。
      另外,最重要的,不要只从“重写”、“继承”等等肤浅的角度去分析问题,也不要轻信别人的回复(包括我的回复)、甚至ThinkingInJava、Java核心技术的相关解释之后,就把问题丢在一边;调试和分析JDK源码,才是掌握知识的最权威、最直接的方式!
    顶,说的很好!
    楼主闲下来的时间可以看看HashMap的实现
    简单的说jdk中的Map都是采用的内部哈希,HashMap的底层实现
    就像是一个“链表数组”,解决hash冲突的办法就是“拉链法”。
    前不久刚刚研究了下源码楼主可参考下:
     http://blog.csdn.net/kiritor/article/details/8886696
      

  11.   

    不能选择F,因为hashcode()再怎么重写,它只能决定拿map key是否容易一些;根据map key去拿map entry,是否容易取决于map.get(mapKey)
      

  12.   

     仅仅对于HashSet、HashMap之类的哈希表,“equals()的两个对象,hashcode()必须相等,否则,没用”是正确的。
      JDK的所有哈希表均采用拉链法解决哈希冲突,当你调用put()方法的时候,JDK会先算出对象的hashcode(),如果此hashcode对应的链表为空,则会直接插入;否则将遍历整个链表,依次调用已经存在的元素的equals()进行比较;如果equals()==true,则不插入,break;当遍历完整个链表之后,说明这个链表所有对象的equals()==false,把新的对象插入到链表头部。
      如果想使用JDK的哈希表,一般无需重写hashcode,因为Object自带的hashcode做的很好,在数据量不大的情况下,不会有任何冲突,CRUD的复杂度均为O(1)。
      但当数据量非常大时,如:超过千万级,对象的hashcode难免会出现重复;如果数据量更大,则冲突会更加严重,哈希表的CRUD效率将逐渐退化为O(sqrt(N))。此时,你就可以重写hashcode来减少冲突。或者重写compareTo方法,使用TreeMap,对于超大数据量,TreeMap的效率是O(log2N),反而好于HashMap。
      另外,最重要的,不要只从“重写”、“继承”等等肤浅的角度去分析问题,也不要轻信别人的回复(包括我的回复)、甚至ThinkingInJava、Java核心技术的相关解释之后,就把问题丢在一边;调试和分析JDK源码,才是掌握知识的最权威、最直接的方式!
    没太明白