zoukankan      html  css  js  c++  java
  • Java hashCode 和 equals

      当向Set集合中插入对象时,如何判别在集合中是否已经存在该对象。如果采用equals方法对元素逐一进行比较,这样的做法较为耗时。可以先判断hashcode值,HashMap中用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去;如果存在该值, 就调用它的equals方法与新元素进行比较,相同则不存,不同则散列到其他位置。这样当数据量大时就减少了equals函数的调用,极大地提高了效率。

    1. Equals

    Object类:直接比较两个对象的地址

    public boolean equals(Object obj) {  
        return (this == obj);  
    }  

    String类:比较对象的内容,Math、Integer、Double等类中的equals函数也是进行内容的比较

    public boolean equals(Object anObject) {  
        if (this == anObject) {  
            return true;  
        }  
        if (anObject instanceof String) {  
            String anotherString = (String)anObject;  
            int n = count;  
            if (n == anotherString.count) {  
                char v1[] = value;  
                char v2[] = anotherString.value;  
                int i = offset;  
                int j = anotherString.offset;  
                while (n– != 0) {  
                    if (v1[i++] != v2[j++])  
                        return false;  
                }  
                return true;  
            }  
        }  
        return false;  
    }

    2. Hashcode

      hashcode对于list集合没有什么意义,但对HashMap、HashSet、HashTable的存取有重要作用。在Java中hashCode方法的主要作用是为了配合基于散列的集合一起正常运行。hashcode的计算是根据对象的属性进行散列的,过多属性参与散列会降低集合的存取效率,太少则容易发生散列冲突, 从而影响hash列表的性能。

    Object类:默认情况下是根据存储地址进行映射

    public native int hashCode();

    String类:

    public int hashCode() {  
        int h = hash;  
        if (h == 0) {  
            int off = offset;  
            char val[] = value;  
            int len = count;  
      
            for (int i = 0; i < len; i++) {  
                h = 31 * h + val[off++];  
            }  
            hash = h;  
        }  
        return h;  
    }

    3. hashcode和equals函数的关系:

      1)  如果两个对象相同(equals比较相等),那么它们的hashCode值一定要相同。

        这样就不会导致两个相同的对象因为hashCode值不一样而同时存入HashMap, 而HashMap不允许存放重复元素

      2) 如果两个对象的hashCode相同,它们并不一定相同,这里的对象相同指的是用equals方法比较。

      3) 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个整数值。

    · 在重写equals方法的同时,必须重写hashCode方法

    package com.sa.io;
    
    import java.util.HashMap;
    
    class People {
        private String name;
        private int age;
        
        public People(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        @Override
        public boolean equals(Object obj) {
            return name.equals(((People)obj).name) && age == ((People)obj).age;
        }
    }
    
    public class HashCodeTest {
        public static void main(String[] args) {
            HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
            hashMap.put(new People("kelly", 18), 1);
            System.out.println(hashMap.get(new People("kelly", 18)));     
            // 返回值为null, 因为People只重写了equals函数没有重写hashcode函数,
            // 默认情况下,hashCode方法是将对象的存储地址进行映射。这里生成了两个对象,存储地址不一样,因此查找不到该对象
        }
    }

    · hashCode函数依赖的字段变化时,hashCode值也发生变化

    class People {
        private String name;
        private int age;
        
        public People(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
        @Override
        public int hashCode() {
            return name.hashCode() * 27 + age;
        }
        
        @Override
        public boolean equals(Object obj) {
            return name.equals(((People)obj).name) && age == ((People)obj).age;
        }
    }
    
    public class HashCodeTest {
        public static void main(String[] args) {
            HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
            People people = new People("kelly", 18);
            hashMap.put(people, 1);
            people.setAge(23);
            System.out.println(hashMap.get(people));     
         // 返回值为null, 因为age是hashcode函数依赖的属性,该值发生变化后hashcode值也改变
         // 如果没有重写hashcode函数,则equals返回true, 然而结果却返回1。因为get方法先用==判断对象是否相同,然后才调用equals
    } }

    HashMap的get方法

    public V get(Object key) {
            if (key == null)
                return getForNullKey();
            int hash = hash(key.hashCode());
            for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k)))   // hash -> (key) ==  -> equals
                    return e.value;
            }
            return null;
    }
  • 相关阅读:
    繁体解决方案一,ASP,JSP,PHP,DotNet任何开发通用
    18.观察者模式(Observer Pattern)
    存储过程小技巧(2)从动态查询SQL中返回值给变量
    DotNet学习
    询问:有没有用C#写的C/S模式下的网页编辑工具
    dotNet繁体解决方案
    svn感叹号大全
    svn中出现红色感叹号
    Varnish配置,Error 503解决之道
    varnish清除缓存的方法
  • 原文地址:https://www.cnblogs.com/anxiao/p/6733955.html
Copyright © 2011-2022 走看看