zoukankan      html  css  js  c++  java
  • Java 重写hashCode()与equals()

    为什么要重写hashCode() 和 equals()

    equals()

    默认的Object类里面equals()方法是根据对象所在的内存来做判断的,如果两个对象引用指向的是同一个内存,则返回true,但是,在某些场景一下,我们不想这么苛刻,比如是String类的equals(),只是判断了String.value的值,String其它的属性是不参与判断的,所以我们比较字符串的时候只是比较其中的内容,下面是String的equals()方法和hashCode()方法。

    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
    
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

     hashCode()

    一般而言,默认的hashCode()方法会返回一个与对象的内存地址相关的值,有时候直接就是内存地址;所以,如何两个对象的hashCode()不相等,则它们肯定是不相等;但反过来,如果两个对象的hashCode()相等,它们不一定是相等的。

    如果我们创建了属于自己的Class,还使用默认的hashCode()方法,那就可以出错,特别是在使用该Class作为HashMap的Key的时候。

    重写hashCode()的基本原则

    该基本原则是参考《Effective Java》Joshua Bloch's recipe

    A、初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
    B、选取equals方法中用于比较的所有域(之所以只选择equals()中使用的域,是为了保证上述原则的第1条),然后针对每个域的属性进行计算:
    (1) boolean,c = f ? 1:0
    (2) bytecharshortint,  c= (int)f
    (3) long,c = (int)(f ^ (f >>> 32))
    (4) float,c = Float.floatToIntBits(f)
    (5) double,long l = Double.doubleToLongBits(f),c = (int)(l ^ (l >>> 32))
    (6) Object,对里面的属性采用上面同一的方法来判断
    (7) 如果是数组,那么需要为每个元素当做单独的域来处理。java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。
    (8)、最后,把每个域的散列码合并到对象的哈希码中。

    一个具体例子

    public class Person {
    
        private String name;
    
        private byte[] password ;
    
        private String nickname ; // ignore the nickname
    
        private int age ;
    
        private double height ;
    
        private long birthYear ;
    
        private float sex ;
    
        private boolean alive;
    
        public Person(String name, byte[] password, int age, double height, long birthYear, float sex, boolean alive , String nickname) {
            this.name = name;
            this.password = password;
            this.nickname = nickname;
            this.age = age;
            this.height = height;
            this.birthYear = birthYear;
            this.sex = sex;
            this.alive = alive;
        }
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public byte[]  getPassword() {
            return password;
        }
    
        public void setPassword(byte[]  password) {
            this.password = password;
        }
    
        public String getNickname() {
            return nickname;
        }
    
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public double getHeight() {
            return height;
        }
    
        public void setHeight(double height) {
            this.height = height;
        }
    
        public long getBirthYear() {
            return birthYear;
        }
    
        public void setBirthYear(long birthYear) {
            this.birthYear = birthYear;
        }
    
        public float getSex() {
            return sex;
        }
    
        public void setSex(float sex) {
            this.sex = sex;
        }
    
        public boolean isAlive() {
            return alive;
        }
    
        public void setAlive(boolean alive) {
            this.alive = alive;
        }
    
        /**
         * Joshua Bloch's recipe
         * @return int
         */
        @Override
        public int hashCode() {
            int result = 17 ;
            result = 37 * result + name.hashCode();
            result = 37 * result + Arrays.hashCode(password);
            result = 37 * result + age;
            long l = Double.doubleToLongBits(height);
            result = 37 * result + (int)(l ^ (l >>> 32));
            result = 37 * result + (int)(birthYear ^ (birthYear >>> 32));
            result = 37 * result + Float.floatToIntBits(sex);
            result = 37 * result + (alive ? 0 : 1 );
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj){
                return true;
            }
            if (obj instanceof Person){
                Person anotherPerson = (Person)obj;
                if (this.getName().equals(anotherPerson.getName())
                        && Arrays.equals(this.getPassword(),anotherPerson.getPassword())
                        && this.age == anotherPerson.getAge()
                        && this.height == anotherPerson.getHeight()
                        && this.birthYear == anotherPerson.getBirthYear()
                        && this.sex == anotherPerson.getSex()
                        && this.alive == anotherPerson.isAlive()
                        ){
                    return true;
                }else {
                    return false;
                }
            }
            return false;
        }
    }
    
    public class Main {
    
        public static void main(String[] args) {
            String  name = "Tom";
            byte [] password = "123".getBytes();
            int age = 18 ;
            double height = 3.14;
            long birthYear = 2000 ;
            float sex  = 1 ;
            boolean alive = true ;
            Person Tom  = new Person(name,password,age,height,birthYear,sex,alive,"Tom");
            Person Deal = new Person(name,password,13,height,birthYear,sex,alive,"Deal");
            Person Jack = new Person(name,password,age,height,birthYear,sex,alive,"Jack");
    
            // map是根据hashcode来判断的,然后还有疑惑,尝试把 Person.hashcode函数注释再运行程序,你会明白
            Map<Person,String> personStringMap = new HashMap<Person, String>(10);
            personStringMap.put(Tom,"Tom");
            personStringMap.put(Deal,"Deal");
    
            System.out.println("Tom's nickname is : "+personStringMap.get(Tom));
            System.out.println("Jack's nickname is : "+personStringMap.get(Jack));
            System.out.println("Deal's nickname is : "+personStringMap.get(Deal));
            System.out.println("is Tom equals to Jack : "+Tom.equals(Jack));
    
            // list 的contains 是根据equal方法来判断的
            List<Person> persons = new ArrayList<Person>();
            persons.add(Tom);
            persons.add(Deal);
            System.out.println("persons contains Jack: " + persons.contains(Jack));
            System.out.println("persons contains Deal: " + persons.contains(Deal));
        }
    }

     参考 http://www.cnblogs.com/kismetv/p/7191736.html

     参考 https://www.cnblogs.com/dolphin0520/p/3681042.html

  • 相关阅读:
    MySQL 8.0 复制延迟观测新方式
    同一台交换机不能相互访问?
    这地方怪怪的
    虾米事情都要在5月30日以前完成
    我搬新家了
    痛恨财务的……
    关于Android Studio Arctic Fox版本找不到Database Inspection这件事
    部署SpringBoot项目到腾讯云或其他服务器
    Object.keys方法之详解
    博客园新随笔 添加锚点
  • 原文地址:https://www.cnblogs.com/chenjingquan/p/9088176.html
Copyright © 2011-2022 走看看