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;
    }
  • 相关阅读:
    Entity SQL 初入
    ObjectQuery查询及方法
    Entity Framework 的事务 DbTransaction
    Construct Binary Tree from Preorder and Inorder Traversal
    Reverse Linked List
    Best Time to Buy and Sell Stock
    Remove Duplicates from Sorted Array II
    Reverse Integer
    Implement Stack using Queues
    C++中const限定符的应用
  • 原文地址:https://www.cnblogs.com/anxiao/p/6733955.html
Copyright © 2011-2022 走看看