hashcode_hashcode方法 - CSDN
hashcode 订阅
哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法。 展开全文
哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法。
信息
外文名
HashCode
包    括
equals和HashCode
类    别
一种算法
中文名
哈希码
应    用
java编程
应用代码类别
Object类,String类,Integer类
哈希码简介
在Java中,哈希码代表对象的特征。例如对象 String str1 = “aa”, str1.hashCode= 3104String str2 = “bb”, str2.hashCode= 3106String str3 = “aa”, str3.hashCode= 3104根据HashCode由此可得出str1!=str2,str1==str3下面给出几个常用的哈希码的算法。1、Object类的hashCode.返回对象的 [1]  内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。2、String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。3、Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。
收起全文
精华内容
参与话题
  • hashCode是什么?

    千次阅读 2018-11-14 22:22:32
    hashCode:散列码是由对象导出的一个整型值。散列码是没有规律的。类的hashCode()方法继承自Object类,因此每个对象都有一个默认的散列码,他的值为对象的存储地址(由对象的物理存储地址通过散列转换来的)。 看...

    hashCode:散列码是由对象导出的一个整型值。散列码是没有规律的。类的hashCode()方法继承自Object类,因此每个对象都有一个默认的散列码,他的值为对象的存储地址(由对象的物理存储地址通过散列转换来的)。

    看下边这个例子:

    package test;
    
    public class Main {
    	public static void main(String[] args) {
    		String str1 = "OK";
    		StringBuffer str2 = new StringBuffer(str1);
    		String str3 = new String(str1);
    		StringBuilder str4 = new StringBuilder(str1);
    		System.out.println(str1.hashCode());
    		System.out.println(str2.hashCode());
    		System.out.println(str3.hashCode());
    		System.out.println(str4.hashCode());
    	}
    }
    

    输出结果:

    其中str1和str3拥有相同的散列码,这是因为字符串的散列码是由内容导出的。而字符串穿缓冲str2和str4的却不想等,这是因为他俩没有hashCode方法,他们的散列码由Object的hashCode方法导出的对象的存储地址。

    展开全文
  • equals和hashcode总结

    万次阅读 多人点赞 2019-07-31 18:37:06
    equals和hashcode总结: 1.equals方法没有重写的话,用于判断对象的内存地址引用是否是用一个地址。重写之后一般用来比较对象的内容是否相等(比如student对象,里面有姓名和年龄,我们重写 equals方法来判断只要...

    equals和hashcode总结:

    1.equals方法没有重写的话,用于判断对象的内存地址引用是否是用一个地址。重写之后一般用来比较对象的内容是否相等(比如student对象,里面有姓名和年龄,我们重写

    equals方法来判断只要姓名和年龄相同就认为是用一个学生)。

    2.hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值,当然你也可以重写它,hashcode方法只有在集合中用到。

    3.对象放入集合中时,先判断hashcode是否相等,再判断equals是否相等,都相等就算是同一个对象,list则可以放入,set因为不允许重复所以不会放入。

    4.例如:

    public class Student {

            private int age;

            private String name;

            

            public Student(int age ,String name){

                this.age = age;

                this.name = name;

            }

            

            public int getAge() {

                return age;

            }

            public void setAge(int age) {

                this.age = age;

            }

            public String getName() {

                return name;

            }

            public void setName(String name) {

                this.name = name;

            }

            //重写equals方法,判断姓名和年龄相同就是相等的

            public boolean equals(Object o){

                if(o == null){

                    return false;

                }

                if(this.getClass() != o.getClass()){

                 return false;   

                }

                Student student = (Student)o;

                if(name == null){

                    return false;

                }

                if(age==student.getAge()&&name.equals(student.getName())){

                    return true;

                }

                return false;

            }

            

        public static void main(String[] args) {

            Student studentOne = new Student(1,"yjc");

            Student studentTwo = new Student(1,new String("yjc"));

            System.out.println(studentOne.equals(studentTwo));

            System.out.println("1: "+studentOne.getName().hashCode());

            System.out.println("2: "+studentTwo.getName().hashCode());

        }

        //输出结果:true

                    1: 119666

                    2: 119666

     

    }

    以上可以看出,两个String都叫"yjc",无论是直接"yjc"还是new String("yjc"),他们的hashcode都相同。所以在重写hashcode方法时可以运用这一点。

    比如你希望如果姓名和年龄相同,不仅equals相同,他们的hashcode也要相同,可以这样重写hashcode:

    public int hashcode(){

    final int prime = 31;

    int result = 1;

    result = prime*result + age;

    result = prime*result + (name == null? 0 : name.hashcode());

    return result;//直接写age+(name == null? 0 : name.hashcode())也行就是感觉太简单了0.0

    }

    这样一来两个姓名和年龄相同的Student对象就是同一个对象了,放入set中会被认为是同一个,无论放几个这样的对象,set.size()都是等于1。

    同样,HashMap因为key也是唯一的,HashMap对象是根据其Key的hashCode来定位存储位置,并使用equals(key)获取对应的Value,所以在put时判断key是否重复用到了hashcode和equals,若重复了则会覆盖。

    展开全文
  • HashCode详解

    千次阅读 多人点赞 2018-09-27 17:56:04
    HashCode详解 起初的时候我一直认为hashcode是内存地址的一个映射,但是今天仔细研究了一下hashcode,以往的认识就这样无情的被颠覆了。 起初我把对象的内存地址和hashcode一起输出,由于java是不建议用户之间操作...

    HashCode详解

    起初的时候我一直认为hashcode是内存地址的一个映射,但是今天仔细研究了一下hashcode,以往的认识就这样无情的被颠覆了。

    起初我把对象的内存地址和hashcode一起输出,由于java是不建议用户之间操作内存的,所以一般情况下是不能够拿到对象的内存地址,但是Java留了一个后门:Unsafe,通过Unsafe类我们可以访问到对象的内存地址

    public class Test {
        private static Unsafe unsafe;
    
        static {
            try {
                Field field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);
                unsafe = (Unsafe) field.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static long addressOf(Object o) throws Exception {
            Object[] array = new Object[]{o};
            long baseOffset = unsafe.arrayBaseOffset(Object[].class);
            int addressSize = unsafe.addressSize();
            long objectAddress;
            switch (addressSize) {
                case 4:
                    objectAddress = unsafe.getInt(array, baseOffset);
                    break;
                case 8:
                    objectAddress = unsafe.getLong(array, baseOffset);
                    break;
                default:
                    throw new Error("unsupported  address  size:  " + addressSize);
            }
            return (objectAddress);
        }
    
    
        public static void main(String[] args) throws Exception {
            Test test=new Test();
            System.out.println(addressOf(test));
            System.out.println(System.identityHashCode(test));
    
            Test test2=new Test();
            System.out.println(addressOf(test2));
            System.out.println(System.identityHashCode(test2));
    
            Test test3=new Test();
            System.out.println(addressOf(test3));
            System.out.println(System.identityHashCode(test3));
        }
    }
    

    我反复运行上面这段代码,结果如下

    第一次 第二次 第三次
    4028048182
    1956725890
    4028048279
    356573597
    4028048324
    1735600054
    4028048091
    1956725890
    4028048188
    356573597
    4028048233
    1735600054
    4028048190
    1956725890
    4028048287
    356573597
    4028048332
    1735600054

    我们可以看到,内存地址不一样,但是hashcode是一样的,更有意思的是hashcode好像和new对象的顺序有关。
    为了验证是否hashcode是否和对象生成的顺序有关,我用一个死循环去循环生成对象,然后看出现hash冲突的位置。

    public class SameClassRepetTest {
        public static void main(String[] args) {
            HashSet<Integer> set=new HashSet<Integer>();
            int count=0;
            int repetCount=0;
            while (true){
                count++;
                int code=new SameClassRepetTest().hashCode();
                if (set.contains(code)){
                    System.out.println("code:"+code);
                    System.out.println("count:"+count);
                    repetCount++;
                    System.out.println(repetCount);
                    if (repetCount==10){
                        break;
                    }
                }
                else
                    set.add(code);
            }
        }
    

    当出现10次重复hashcode的时候程序终止,结果如下

    code:2134400190
    count:105825
    1
    code:651156501
    count:111272
    2
    code:1867750575
    count:121933
    3
    code:2038112324
    count:145456
    4
    code:1164664992
    count:146389
    5
    code:273791087
    count:152369
    6
    code:996371445
    count:180981
    7
    code:254720071
    count:184294
    8
    code:1872358815
    count:186922
    9
    code:332866311
    count:206932
    10

    每一次运行的结果都是相同的,这就很有意思了,基本上初步就可以判断hashcode与对象生成的顺序有关

    然后我生成不同的类对象去重复上述操作

    public class DeffClassRepetTest {
        public static void main(String[] args) {
            HashSet<Integer> set = new HashSet<Integer>();
            int count = 0;
            int repetCount = 0;
            while (true) {
                count++;
                int code = count%2==0?new SameClassRepetTest().hashCode():new DeffClassRepetTest().hashCode();
                if (set.contains(code)) {
                    System.out.println("code:" + code);
                    System.out.println("count:" + count);
                    repetCount++;
                    System.out.println(repetCount);
                    if (repetCount == 10) {
                        break;
                    }
                } else
                    set.add(code);
            }
        }
    }
    
    

    运行结果与同一个类生成对象的结果完全一致,可以断定hashcode与对象类型无关,对象的生成顺序有关。当我以为认识到真相的时候,手贱敲了段代码,结果认识又被颠覆了。

    我用多个线程去执行上述操作:

    public class ConcurrentTest {
        public static void main(String[] args) {
            AtomicInteger count =new AtomicInteger(0);
            AtomicInteger repetCount=new AtomicInteger(0);
            ConcurrentSkipListSet<Integer> set=new ConcurrentSkipListSet<Integer>();
            new Thread(()->{
                while (true) {
                    count.incrementAndGet();
                    int code = count.get()%2==0?new SameClassRepetTest().hashCode():new DeffClassRepetTest().hashCode();
                    if (set.contains(code)) {
                        System.out.println("Tread1:code:" + code);
                        System.out.println("Tread1:count:" + count.get());
                        repetCount.incrementAndGet();
                        System.out.println(repetCount.get());
                        if (repetCount.get() >= 10) {
                            break;
                        }
                    } else
                        set.add(code);
                }
            }).start();
            new Thread(()->{
                while (true) {
                    count.incrementAndGet();
                    int code = count.get()%2==0?new SameClassRepetTest().hashCode():new DeffClassRepetTest().hashCode();
                    if (set.contains(code)) {
                        System.out.println("Tread2:code:" + code);
                        System.out.println("Tread2:count:" + count.get());
                        repetCount.incrementAndGet();
                        System.out.println(repetCount.get());
                        if (repetCount.get() >= 10) {
                            break;
                        }
                    } else
                        set.add(code);
                }
            }).start();
        }
    

    重复运行这段代码

    第一次 第二次
    Tread2:code:308698969
    Tread2:count:133848
    1
    Tread2:code:39252308
    Tread2:count:141446
    2
    Tread2:code:462746542
    Tread2:count:144624
    3
    Tread1:code:699788746
    Tread1:count:158743
    4
    Tread1:code:1745215832
    Tread1:count:172682
    5
    Tread1:code:571947411
    Tread1:count:174724
    6
    Tread1:code:1609797262
    Tread1:count:175730
    7
    Tread1:code:1406244557
    Tread1:count:175922
    8
    Tread1:code:361509194
    Tread1:count:215637
    9
    Tread1:code:476907224
    Tread1:count:217548
    10
    Tread2:code:1600420189
    Tread2:count:222308
    11
    Tread1:code:147103475
    Tread1:count:45814
    1
    Tread2:code:30086540
    Tread2:count:61907
    2
    Tread2:code:222755065
    Tread2:count:73802
    3
    Tread1:code:1370187659
    Tread1:count:105263
    4
    Tread2:code:327698381
    Tread2:count:143654
    5
    Tread2:code:1745215832
    Tread2:count:175517
    6
    Tread2:code:1609797262
    Tread2:count:178438
    7
    Tread2:code:1406244557
    Tread2:count:178628
    8
    Tread2:code:476907224
    Tread2:count:219082
    9
    Tread1:code:1012470049
    Tread1:count:226958
    10
    Tread2:code:345268840
    Tread2:count:245758
    11

    看起来没有任何的规律,这时我就觉得有点茫然了,没办法,于是我开始去扒源码
    Object源码地址
    在Object中我们可以看到hashCode实际上是调用了IHashCode

    static JNINativeMethod methods[] = {
        {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
        {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
        {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
        {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
        {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
    };
    

    然后在jvm.cpp找到了IHashCode实际调用的是FastHashCode

    JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
      JVMWrapper("JVM_IHashCode");
      // as implemented in the classic virtual machine; return 0 if object is NULL
      return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
    JVM_END
    

    接着扒FastHashCode,FastHashCode在synchronizer.cpp

    intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
      if (UseBiasedLocking) {
        // NOTE: many places throughout the JVM do not expect a safepoint
        // to be taken here, in particular most operations on perm gen
        // objects. However, we only ever bias Java instances and all of
        // the call sites of identity_hash that might revoke biases have
        // been checked to make sure they can handle a safepoint. The
        // added check of the bias pattern is to avoid useless calls to
        // thread-local storage.
        if (obj->mark()->has_bias_pattern()) {
          // Box and unbox the raw reference just in case we cause a STW safepoint.
          Handle hobj (Self, obj) ;
          // Relaxing assertion for bug 6320749.
          assert (Universe::verify_in_progress() ||
                  !SafepointSynchronize::is_at_safepoint(),
                 "biases should not be seen by VM thread here");
          BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
          obj = hobj() ;
          assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
        }
      }
    
      // hashCode() is a heap mutator ...
      // Relaxing assertion for bug 6320749.
      assert (Universe::verify_in_progress() ||
              !SafepointSynchronize::is_at_safepoint(), "invariant") ;
      assert (Universe::verify_in_progress() ||
              Self->is_Java_thread() , "invariant") ;
      assert (Universe::verify_in_progress() ||
             ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
    
      ObjectMonitor* monitor = NULL;
      markOop temp, test;
      intptr_t hash;
      markOop mark = ReadStableMark (obj);
    
      // object should remain ineligible for biased locking
      assert (!mark->has_bias_pattern(), "invariant") ;
    	//mark是对象头
      if (mark->is_neutral()) {
        hash = mark->hash();              // 取出hash值(实际上可以理解为缓存,有就直接返回,没有就生成一个新的)
        if (hash) {                       // if it has hash, just return it
          return hash;
        }
        hash = get_next_hash(Self, obj);  // 这是生成hashcode的核心方法
        temp = mark->copy_set_hash(hash); // merge the hash code into header
        // use (machine word version) atomic operation to install the hash
        test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
        if (test == mark) {
          return hash;
        }
        // If atomic operation failed, we must inflate the header
        // into heavy weight monitor. We could add more code here
        // for fast path, but it does not worth the complexity.
      } else if (mark->has_monitor()) {
        monitor = mark->monitor();
        temp = monitor->header();
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();
        if (hash) {
          return hash;
        }
        // Skip to the following code to reduce code size
      } else if (Self->is_lock_owned((address)mark->locker())) {
        temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();              // by current thread, check if the displaced
        if (hash) {                       // header contains hash code
          return hash;
        }
        // WARNING:
        //   The displaced header is strictly immutable.
        // It can NOT be changed in ANY cases. So we have
        // to inflate the header into heavyweight monitor
        // even the current thread owns the lock. The reason
        // is the BasicLock (stack slot) will be asynchronously
        // read by other threads during the inflate() function.
        // Any change to stack may not propagate to other threads
        // correctly.
      }
    
      // Inflate the monitor to set hash code
      monitor = ObjectSynchronizer::inflate(Self, obj);
      // Load displaced header and check it has hash code
      mark = monitor->header();
      assert (mark->is_neutral(), "invariant") ;
      hash = mark->hash();
      if (hash == 0) {
        hash = get_next_hash(Self, obj);
        temp = mark->copy_set_hash(hash); // merge hash code into header
        assert (temp->is_neutral(), "invariant") ;
        test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
        if (test != mark) {
          // The only update to the header in the monitor (outside GC)
          // is install the hash code. If someone add new usage of
          // displaced header, please update this code
          hash = test->hash();
          assert (test->is_neutral(), "invariant") ;
          assert (hash != 0, "Trivial unexpected object/monitor header usage.");
        }
      }
      // We finally get the hash
      return hash;
    }
    

    get_next_hash

    static inline intptr_t get_next_hash(Thread * Self, oop obj) {
      intptr_t value = 0 ;
      //随机获取一个
      if (hashCode == 0) {
         // This form uses an unguarded global Park-Miller RNG,
         // so it's possible for two threads to race and generate the same RNG.
         // On MP system we'll have lots of RW access to a global, so the
         // mechanism induces lots of coherency traffic.
         value = os::random() ;
      } else
      //根据内存地址计算一个
      if (hashCode == 1) {
         // This variation has the property of being stable (idempotent)
         // between STW operations.  This can be useful in some of the 1-0
         // synchronization schemes.
         intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
         value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
      } else
      //返回1
      if (hashCode == 2) {
         value = 1 ;            // for sensitivity testing
      } else
      //不太清楚什么意思 求大佬解释
      if (hashCode == 3) {
         value = ++GVars.hcSequence ;
      } else
      //直接返回内存地址
      if (hashCode == 4) {
         value = cast_from_oop<intptr_t>(obj) ;
      }
      //这是一种生成随机数的一种算法
       else {
         // Marsaglia's xor-shift scheme with thread-specific state
         // This is probably the best overall implementation -- we'll
         // likely make this the default in future releases.
         unsigned t = Self->_hashStateX ;
         t ^= (t << 11) ;
         Self->_hashStateX = Self->_hashStateY ;
         Self->_hashStateY = Self->_hashStateZ ;
         Self->_hashStateZ = Self->_hashStateW ;
         unsigned v = Self->_hashStateW ;
         v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
         Self->_hashStateW = v ;
         value = v ;
      }
    
      value &= markOopDesc::hash_mask;
      if (value == 0) value = 0xBAD ;
      assert (value != markOopDesc::no_hash, "invariant") ;
      TEVENT (hashCode: GENERATE) ;
      return value;
    }
    

    到了这里我们基本上就知道了hashcode是怎么生成的了,实际上在jdk1.8在是用的第五种生成方式,我们可以在Linux系统下输入:java -XX:+PrintFlagsFinal -version|grep hashCode命令查看
    在这里插入图片描述
    ok,接下来我们来分析一下第5种方式,看到这个代码我的第一反应是懵逼的,那个什么_hashStateX是个什么鬼?
    我们来看一下thead.cpp里面是怎样定义的:

    // thread-specific hashCode stream generator state - Marsaglia shift-xor form
      _hashStateX = os::random() ;
      _hashStateY = 842502087 ;
      _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
      _hashStateW = 273326509 ;
    

    在thread里面定义了一个随机数,三个常数,通过这四个数根据上述的算法来生成hashcode。

    具体原理请参考论文:Xorshift RNGs

    因为在上述算法在,需要得到线程里面的一个随机数作为一个初始值,上述算法在前后具有因果关系,后面的结果是根据前面的结果推算而来的,因此对于相同的线程来说,在某种意义上,对象的hashcode的生成是和顺序有关的。

    为什么主函数里面的hashcode的生成一直是有序的呢?我猜测是主线程里面的——hashStateX是一个固定值(未证实)

    可见hashcode在1.8中和内存地址是无关的,与所在线程(或者说生成的一个随机数)以及生成顺序有关

    展开全文
  • 必须掌握的hashcode()方法

    万次阅读 多人点赞 2019-06-16 18:47:07
    一、hashcode是什么? 1、hash和hash表是什么?  想要知道这个hashcode,首先得知道hash,通过百度百科看一下: hash是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值。这个...

    一、hashcode是什么?

    1、hash和hash表是什么?   

    想要知道这个hashcode,首先得知道hash,通过百度百科看一下:

    hash是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值。这个时候,我们就需要知道另一个东西,hash表,通过hash算法得到的hash值就在这张hash表中,也就是说,hash表就是所有的hash值组成的,有很多种hash函数,也就代表着有很多种算法得到hash值,如上面截图的三种,等会我们就拿第一种来说。

    2、hashcode 

    有了前面的基础,这里讲解就简单了,hashcode就是通过hash函数得来的,通俗的说,就是通过某一种算法得到的,hashcode就是在hash表中有对应的位置。

    每个对象都有hashcode,对象的hashcode怎么得来的呢?

    首先一个对象肯定有物理地址,在别的博文中会hashcode说成是代表对象的地址,这里肯定会让读者形成误区,对象的物理地址跟这个hashcode地址不一样,hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址,那么对象如何得到hashcode呢?

    通过对象的内部地址(也就是物理地址)转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode。所以,hashcode是什么呢?就是在hash表中对应的位置。

    这里如果还不是很清楚的话,举个例子,hash表中有 hashcode为1、hashcode为2、(…)3、4、5、6、7、8这样八个位置,有一个对象A,A的物理地址转换为一个整数17(这是假如),就通过直接取余算法,17%8=1,那么A的hashcode就为1,且A就在hash表中1的位置。

    肯定会有其他疑问,接着看下面,这里只是举个例子来让你们知道什么是hashcode的意义。

    二、hashcode有什么作用呢?

    前面说了这么多关于hash函数,和hashcode是怎么得来的,还有hashcode对应的是hash表中的位置,可能大家就有疑问,为什么hashcode不直接写物理地址呢,还要另外用一张hash表来代表对象的地址?接下来就告诉你hashcode的作用,

    1、HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的(后半句说的用hashcode来代表对象就是在hash表中的位置)

    为什么hashcode就查找的更快,比如:我们有一个能存放1000个数这样大的内存中,在其中要存放1000个不一样的数字,用最笨的方法,就是存一个数字,就遍历一遍,看有没有相同得数,当存了900个数字,开始存901个数字的时候,就需要跟900个数字进行对比,这样就很麻烦,很是消耗时间,用hashcode来记录对象的位置,来看一下。

    hash表中有1、2、3、4、5、6、7、8个位置,存第一个数,hashcode为1,该数就放在hash表中1的位置,存到100个数字,hash表中8个位置会有很多数字了,1中可能有20个数字,存101个数字时,他先查hashcode值对应的位置,假设为1,那么就有20个数字和他的hashcode相同,他只需要跟这20个数字相比较(equals),如果每一个相同,那么就放在1这个位置,这样比较的次数就少了很多,实际上hash表中有很多位置,这里只是举例只有8个,所以比较的次数会让你觉得也挺多的,实际上,如果hash表很大,那么比较的次数就很少很少了。

    通过对原始方法和使用hashcode方法进行对比,我们就知道了hashcode的作用,并且为什么要使用hashcode了

    三、equals方法和hashcode的关系?

    通过前面这个例子,大概可以知道,先通过hashcode来比较,如果hashcode相等,那么就用equals方法来比较两个对象是否相等。

    用个例子说明:上面说的hash表中的8个位置,就好比8个桶,每个桶里能装很多的对象,对象A通过hash函数算法得到将它放到1号桶中,当然肯定有别的对象也会放到1号桶中,如果对象B也通过算法分到了1号桶,那么它如何识别桶中其他对象是否和它一样呢,这时候就需要equals方法来进行筛选了。

    1、如果两个对象equals相等,那么这两个对象的HashCode一定也相同

    2、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

    这两条你们就能够理解了。

    四、为什么equals方法重写的话,建议也一起重写hashcode方法?

    如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写

    举个例子,其实就明白了这个道理,

    比如:有个A类重写了equals方法,但是没有重写hashCode方法,看输出结果,对象a1和对象a2使用equals方法相等,按照上面的hashcode的用法,那么他们两个的hashcode肯定相等,但是这里由于没重写hashcode方法,他们两个hashcode并不一样,所以,我们在重写了equals方法后,尽量也重写了hashcode方法,通过一定的算法,使他们在equals相等时,也会有相同的hashcode值。

    实例:现在来看一下String的源码中的equals方法和hashcode方法。这个类就重写了这两个方法,现在为什么需要重写这两个方法了吧?

    equals方法:其实跟我上面写的那个例子是一样的原理,所以通过源码又知道了String的equals方法验证的是两个字符串的值是否一样。还有Double类也重写了这些方法。很多类有比较这类的,都重写了这两个方法,因为在所有类的父类Object中。equals的功能就是 “==”号的功能。你们还可以比较String对象的equals和==的区别啦。这里不再说明。

    hashcode方法

    展开全文
  • 最详细的equal和hashcode详解

    万次阅读 多人点赞 2020-01-08 20:45:47
    hashcode() 方法详解 Hashset、Hashmap、Hashtable与hashcode()和equals()的密切关系 java.lang.Object类中有两个非常重要的方法: 1 2 publicbooleanequals(Object obj) ...
  • I、 hashCode()方法是Object类下面的一个方法,供继承类重写,根据对象内存地址计算哈希值, String类重写了hashCode方法,并改为根据字符序列来计算哈希值 III、identityHashCode()方法是System类中的静态...
  • 我们都知道,Java对象头的结构如下: 内容 说明 备注 Mark Word 存储对象的Mark Word信息 - Class Metadata Address 存储指向对象存储类型的指针 ... 其中,在32位机器下,Mark Word的存储结构...
  • hashCode 我们知道在Java中,一切对象都继承自java.lang.Object类。这个类中有一个可继承的方法叫hashCode()。它在Object类中的方法签名是这样的: public native int hashCode(); 可以看到,如果一个对象不覆盖...
  • 如果重写 equals 不重写 hashcode 会有什么影响? 这个问题从上午10:45 开始陆续讨论,到下午15:39 接近尾声 (忽略这形同虚设的马赛克) 这是一个好问题,更是一个高频基础面试题,我还曾经专门写过一篇文章 Java...
  • Java中hashCode的作用

    万次阅读 多人点赞 2013-05-09 13:54:53
    以下是关于HashCode的官方文档定义: hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 hashCode 的常规协定是: 在 Java 应用程序执行期间,...
  • Hash和HashCode深入理解

    千次阅读 2018-10-17 18:32:50
    目录介绍 1.Hash的作用介绍 1.1 Hash的定义 1.2 Hash函数特性 ...3.HashCode深入分析 ...3.0 HashCode是什么 ...3.1 为什么要重写HashCode 3.2 HashCode源代码分析 3.3 HashCode带来的疑问 ...
  • 为什么重写equals一定要重写hashcode

    万次阅读 多人点赞 2020-06-19 22:24:31
    大家都知道,equals和hashcode是java.lang.Object类的两个重要的方法,在实际应用中常常需要重写这两个方法,但至于为什么重写这两个方法很多人都搞不明白,以下是我的一些个人理解。 这是Object类关于这两个方法...
  • hashCode()相同,equals() 也一定为 true吗?

    万次阅读 热门讨论 2020-10-04 19:59:49
    两个对象hashCode()相同,equals() 也一定为 true吗? 首先,答案肯定是不一定。同时反过来equals为true,hashCode也不一定相同。 类的hashCode方法和equals方法都可以重写,返回的值完全在于自己定义。 ...
  • 浅见equals()与hashCode()之间的关系

    万次阅读 2018-08-18 10:43:21
    1.Java对于equals()方法和hashCode()方法的规定 如果两个对象equals()方法相等则它们的hashCode返回值一定要相同,如果两个对象的hashCode返回值相同,但它们的equals()方法不一定相等。 两个对象的hashCode()...
  • 浅谈Object的hashCode方法的作用

    千次阅读 2018-06-11 08:31:40
    Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。 其主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括...
  • hashCode是所有java对象的固有方法,如果不重载的话,返回的实际上是该对象在jvm的堆上的内存地址,而不同对象的内存地址肯定不同,所以这个hashCode也就肯定不同了。如果重载了的话,由于采用的算法的问题,有可能...
  • Java如何计算hashcode

    万次阅读 2014-10-21 10:18:32
    在重写类的hashCode()方法时,我们
  • Java中String类的hashCode()方法

    千次阅读 2019-05-09 17:47:03
    相同的字符串调用hashCode()方法,得到的值是一样的,与内存地址、进程、机器无关。String类的hashCode()方法的源码如下: public int hashCode() { int h = hash; // 默认值是0 if (h == 0 && value....
  • 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? 结论: 两个对象equals相等,则它们的hashcode必须相等,反之则不一定。 两个对象==相等,则其hashcode一定相等,反之不一定成立。 hashCode 的...
  • 为什么重写equals还要重写hashcode

    千次阅读 2019-05-18 21:05:04
    14、● 请你解释Object若不重写hashCode()的话,hashCode()如何计算出来的? 考点:基础 参考回答: Object 的 hashcode 方法是本地方法,也就是用 c 或 c++ 实现的,该方法直接返回对象的内存地址。 如果没有重写...
1 2 3 4 5 ... 20
收藏数 205,626
精华内容 82,250
关键字:

hashcode