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对象,返回的哈希码也一样。
收起全文
精华内容
下载资源
问答
  • 主要介绍了java 中HashCode重复的可能性的相关资料,这里提供实例及测试代码,需要的朋友可以参考下
  • 主要介绍了javascript中实现兼容JAVA的hashCode算法代码分享,实现跟JAVA中的运算结果一致,需要的朋友可以参考下
  • Object 类是所有类的父类,其 equals 方法比较的是两个对象的引用指向的地址,hashcode 是一个本地方法,返回的是对象地址值。他们都是通过比较地址来比较对象是否相等的
  • 主要给大家介绍了关于java中为什么重写equals时必须重写hashCode方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • Java提高篇之hashCode

    2020-12-22 22:36:56
    在前面三篇博文中LZ讲解了(HashMap、HashSet、HashTable),在其中LZ不断地讲解他们的put和get方法,在这两个方法中计算key的hashCode应该是重要也是精华的部分,所以下面LZ揭开hashCode的“神秘”面纱。...
  • 下面小编就为大家带来一篇java中重写equals()方法的同时要重写hashcode()方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • HashCode

    千次阅读 2019-10-04 09:28:13
    HashCode hashcode /*哈希值:是一个十进制的整数,由系统随机给出(就是一个对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是实际地址) 在object类中有一个方法,可以获得对象的哈希值 int hashcode...

    HashCode

    hashcode

    /*哈希值:是一个十进制的整数,由系统随机给出(就是一个对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是实际地址)

    • 在object类中有一个方法,可以获得对象的哈希值
    • int hashcode()返回该对象的哈希值
    • hashcode方法的源码
    • public native int hashcode();
    • native:代表该方法调用的是本地操作系统的方法*/

    新建一个对象类Person

    代码:

    public class Person extends Object {
    
    }
    

    测试类:

    代码:

    public class Demo01HashCode {
    public static void main(String[] args) {
        Person p1=new Person();
        int h1=p1.hashCode();
        Person p2=new Person();
        int h2=p2.hashCode();
        System.out.println(h1);//1163157884,重写hashcode,放回值为一;
        System.out.println(h2);//1956725890,重写hashcode,放回值为一;
        System.out.println(p1);//cn.itcast.API.HashCode.Person@4554617c
        System.out.println(p2);//cn.itcast.API.HashCode.Person@74a14482
        System.out.println(p1==p2);//false
        /*String类的哈希值
        * String类重写object类的hashCode方法*/
        String s1=new String("abc");
        String s2=new String("abc");
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354
        System.out.println("重地".hashCode());//1179395,巧合!
        System.out.println("通话".hashCode());//1179395
        System.out.println("你是谁:".hashCode());//631668296,一般情况!
        System.out.println("为了谁:".hashCode());//617023717
        HashSet<String> strings = new HashSet<>();
      //set存取hashcode相同的元素
        strings.add("abc");
        strings.add(s1);//地址值相同,且equals相同,不存储
        strings.add(s2);//地址值相同,且equals相同,不存储
        strings.add("重地");//地址值相同,但equals不相同,存储
        strings.add("通话");//地址值相同,但equals不相同,存储
        System.out.println(strings);//[重地, 通话, abc]
    }
    

    显示效果:

    1163157884
    1956725890
    cn.itcast.API.HashCode.Person@4554617c
    cn.itcast.API.HashCode.Person@74a14482
    false
    96354
    96354
    1179395
    1179395
    631668296
    617023717
    [重地, 通话, abc]

    person类中的HashCode方法重写

    代码:

    public class Person extends Object {
        @Override
      public int hashCode()
    {
          return 1;
    }
    }
    

    测试类重写测试显示效果

    1
    1
    cn.itcast.API.HashCode.Person@1
    cn.itcast.API.HashCode.Person@1
    false
    96354
    96354
    1179395
    1179395
    631668296
    617023717
    [重地, 通话, abc]
    重写HashCode后为什么P1和P2的返回值都是相同的p1 == p2还是false,因为p1 == p2比较的是两个实际地址值,而哈希值只是逻辑地址值,是模拟出来的地址

    String s1=new String("abc");
        String s2=new String("abc");
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s1==s2);//false
    

    list存储数据先看两个字符串的哈希值是否相同再看是否Equals(值是否相同)再进行是否存入!
    关于重地和通话哈希值相同为啥能够进入到set中,我们知道set不可以存储相同元素的,哈希值相同,我们还要看元素值equals是否相等,满足这两个条件才存储进set中

    LinkedHashSet

    哈希表和链表实现了Set接口,具有可预测的迭代次序。 这种实现不同于HashSet,它维持于所有条目的运行双向链表
    代码:

    public class LinkedHashSet {
    
    public static void main(String[] args) {
        HashSet<String> set=new HashSet<>();
        set.add("www");
        set.add("baidu");
        set.add("www");
        set.add("com");
        System.out.println(set);
        java.util.LinkedHashSet<String> linked=new java.util.LinkedHashSet<>();
        linked.add("www");
        linked.add("baidu");
        linked.add("com");
        linked.add("baidu");
        System.out.println(linked);//按照原来的顺序,也不接受重复数据!
    }
    }
    

    显示效果:

    [com, www, baidu]
    [www, baidu, com]

    set存储对象时的应用

    定义一个Student类存放对象的属性值
    代码(已经重写了Equals和HashCode方法!,为了简便的观看重写了Tostring方法):

    public class Student {
    private String name;
    private int age;
    
    public Student() {
    }
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    }
    

    测试类

    代码:

    public class StudentDemoTest {
    
    public static void main(String[] args) {
        HashSet<Student> set=new HashSet<>();
        Student stu1=new Student("钱学森",22);
        Student stu2=new Student("钱学森",22);
        Student stu3=new Student("钱伟长",22);
        Student stu4=new Student("钱三强",22);
        System.out.println(stu1.hashCode());
        System.out.println(stu2.hashCode());//hashCode不一样,重写之后一样了!
        System.out.println(stu1==stu2);//false,地址值不一样
        System.out.println(stu1.equals(stu2));//false重写之后true
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        System.out.println(set);
    }
    }
    

    注意点

    存储对象时,必须重写hashcode方法和equals方法!
    重写tostring方法(非必须!将地址值的默认改掉!)

    显示效果

    1157313598
    1157313598
    false
    true
    [Student{name=‘钱三强’, age=22}, Student{name=‘钱伟长’, age=22}, Student{name=‘钱学森’, age=22}]

    展开全文
  • 本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
  • 主要介绍了如何在IDEA中对 hashCode()和 equals() 利用快捷键快速进行方法重写,需要的朋友可以参考下
  • 文章目录1、hashCode与equals两者之间的关系2、== 和equals的区别`3、为什么要重写equals()方法?4、重写equals()方法5、为什么要重写hashCode()方法?6、什么时候需要重写hashCode()方法?7、重写hashCode()方法: ...
  • Google Hashcode 2021分数计算器 计算Google Hashcode 2021资格回合得分。 对于我们提交的内容,其结果与Google相同。 它也为示例文件提供了相同的结果。 注意:对于不正确的提交文件,它可能不够可靠。 注意:...
  • 首先我们看下下面代码及输出和String重写equals和hashcode的源码: package com.zzy.test; public class Test6 { public static void main(String[] args) { String s1="aaa"; String s2="aaa"; String s3=new ...
  • 有许多人学了很长时间的Java,但一直不明白hashCode方法的作用,我来解释一下吧。
  • HashCode详解

    千次阅读 多人点赞 2018-09-27 17:51:09
    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中和内存地址是无关的,与所在线程(或者说生成的一个随机数)以及生成顺序有关

    展开全文
  • 本文中详细的阐述了Java中经常遇到的equals、hashcode以及“==”号三者之间的区别
  • 主要给大家介绍了关于Java中HashCode方法的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • hashcode-源码

    2021-03-30 12:50:55
    hashcode
  • hashcode

    千次阅读 2019-07-12 18:03:43
    hashcode java中的每一个类都继承Object Object类中有一个方法,该方法返回hashcode,native表示调用本地操作系统的方法 任何类都可以重写该方法,例如创建一个Person类并重写该方法,代码如下 public class ...

    hashcode

    • java中的每一个类都继承Object
    • Object类中有一个方法,该方法返回hashcode,native表示调用本地操作系统的方法
      在这里插入图片描述
    • 任何类都可以重写该方法,例如创建一个Person类并重写该方法,代码如下
    public class Person extends Object{
        @Override
        public int hashCode(){
            return 1;
        }
    }
    
            Person p= new Person();
            System.out.println(p);
            Person  p2=new Person();
            System.out.println(p2);
    
    • 结果如下
      在这里插入图片描述
    • 因此@后面表示的是hash值,也可以理解成为逻辑值。但是此时物理地址不一样
    展开全文
  • 主要介绍了深入理解Java中HashCode方法,具有一定借鉴价值,需要的朋友可以参考下
  • PPT浅析hashcode

    2018-12-28 20:42:51
    PPT浅析hashcode定义和作用;和简单的代码演示PPT.很简单的
  • 网上找了好一轮,找到个比较像样而且足够短的 hashCode 实现,是从 Java 的 hashCode 中借鉴而得的。原理见 Java hashCode() ,也可以跟这里的 Java String 的源码 参照对比一下
  • 本文详细解释了JAVA hashCode的使用方法,提供了测试hashCode和equals方法的使用实例
  • 本篇文章主要介绍了Java中的hashcode方法,详细的介绍了hashCode方法的作用,具有一定的参考价值,有需要的可以了解一下。
  •  2、为什么改写equals()的时候,总是要改写hashCode()  两个原则:  hashCode()的返回值和equals()的关系如下:  如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。  如果x.equals(y)返回...
  • hashCode

    千次阅读 2021-04-24 12:13:58
    hashCode原理 hashCode是jdk根据对象的地址算出来的一个int数字,即对象的哈希码值,代表了该对象在内存中的存储位置。 hashCode()方法是顶级类Object类的提供的一个方法,所有的类都可以进行对hashCode方法重写。...

    目录

    hashCode原理

    hashCode冲突解决


    hashCode原理

    • hashCode是jdk根据对象的地址算出来的一个int数字,即对象的哈希码值,代表了该对象在内存中的存储位置。
    • hashCode()方法是顶级类Object类的提供的一个方法,所有的类都可以进行对hashCode方法重写。
    • 比较一个类是否相同时往往会重写equals方法,值得注意的是,重写equals方法的同时必须也要重写hashCode方法,多次调用一个对象的hashCode方法必须返回同一个数字,这也是必须遵守的规范。

    hashCode冲突解决

    概念

        当两个对象equals相同,hashCode规定也必须相同,但反过来就不一定,两个对象对应一个hashCode,但equals却并不相等。这就是hash冲突

    解决方式

    • 1.开放地址方法

      (1)线性探测

       按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上往后加一个单位,直至不发生哈希冲突。 

      (2)再平方探测

       按顺序决定哈希值时,如果哈希值已经存在,则在原来哈希值的基础上先加1的平方个,若仍然存在则减1的平方。随之是2的平方,3的平方等等。直至不发生哈希冲突。

      (3)伪随机探测

       按顺序决定哈希值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来哈希值的基础上加上随机数,直至不发生哈希冲突。

    • 2.链式地址法(HashMap的哈希冲突解决方法)

      对于相同的哈希值,使用链表进行连接。使用数组存储每一个链表。

      优点:

      (1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;

      (2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;

      (3)开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;

      (4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
      缺点:

      指针占用较大空间时,会造成空间浪费,若空间用于增大散列表规模进而提高开放地址法的效率。

    • 3.建立公共溢出区

      建立公共溢出区存储所有哈希冲突的数据。

    • 4.再哈希法

      对于冲突的哈希值再次进行哈希处理,直至没有哈希冲突。

        

    展开全文
  • NULL 博文链接:https://zpointer.iteye.com/blog/1058337
  • hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。下面这篇文章主要给大家介绍了关于java中hashCode、equals的使用方法,需要的朋友可以参考下。
  • HashCode方法

    2021-09-02 16:48:45
    文章目录1、hashCode方法介绍2、hashCode的作用3、eqauls方法和hashCode方法关系4、关于这两个方法的重要规范:5、为什么覆盖equals时总要覆盖hashCode6、总结 1、hashCode方法介绍 hashCode()方法返回的就是一个...
  • 我们的Google Hashcode工作区

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 281,052
精华内容 112,420
关键字:

hashcode