equals和==分析

作者: Taoyongpan | 来源:发表于2018-03-30 21:14 被阅读45次

基本概念

在 Java中 ==是运算符,比较的是两个变量是否相等;
equals()是Object方法,用于比较两个对象是否相等,看一下源码:

 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;
    }

当this==anObject的时候,返回true,即this 和 obj引用同一个对象时,才会返回true;还有就是当判断字符串相等的时候,当anObject是String类型,并且长度和内容一样的时候,返回true;总结一下,只有当引用一个对象的时候,才会返回true。
  而我们在实际用equals()方法的时候,我们往往不是为了判断两个引用的是一个对象,因此我们此时要重写equals()方法;
equals()有以下的公约必须遵守:

  • 自反性:对于任何非null的引用值x,x.equals(x)必须返回true;
  • 对称性:x,y非空,如果x.equals(y)返回true,那么y.equals(x)必为true;
  • 传递性:x,y,z非空,x.equals(y),y.equals(z)返回true,那么x.equals(z)必为true;
  • 一致性:x,y非空,只要对象信息没有被修改,那么多次调用x.equals(y)的结果肯定都一样;
  • 对于任何非null的引用值x,x.equals(null)必须返回false;

因此当我们编写完成了equals()方法的时候,我们要问自己三个问题:它是否是对称的、传递的、一致的;

重写equals()方法的时候总要重写hashcode()方法

  在每个重写equals()的类中,我们必须重写hashcode()方法;如果不这样做,会违反hashcode()的公约:
1.只要对象的信息没有改变,那么对一个对象调用多次,hashcode()方法都必须始终如一的返回同一个整数;
2.如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashcode()方法都必须产生同样的结果;
3.如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashcode()方法不一定产生同样的结果;

相等的对象必须有相同的散列码

代码测试

import java.util.HashSet;
import java.util.Set;

/**
 * Created by Taoyongpan on 2017/4/6.
 * hashcode和equals方法
 * HashMap中有一个put方法,put(key,value)key是无序不可重复的
 */
public class SetTest2 {
    public static void main(String[] args)
    {
        //创建集合
        Set es = new HashSet();

        Employee e1 = new Employee("1000","tao");
        Employee e2 = new Employee("1000","tao");
//        Employee e2 = new Employee("1001","tao1");
        Employee e3 = new Employee("1002","tao2");
        Employee e4 = new Employee("1003","tao3");
        Employee e5 = new Employee("1004","tao4");
        Employee e6 = new Employee("1005","tao5");
//        System.out.println(e1.equals(e2));
//        System.out.println(e2);
        System.out.println(e1.hashCode());
        System.out.println(e2.hashCode());
        es.add(e1);
        es.add(e2);
        es.add(e3);
        es.add(e4);
        es.add(e5);
        es.add(e6);

        System.out.println(es.size());
    }
}

class Employee{
    String num;//员工编号
    String name;

    Employee(String num,String name){
        this.num = num;
        this.name = name;
    }
    //重写equals方法,如果员工编号相同并且名字相同,则是同一个对象
    public boolean equals(Object o){
        if (this == o){
            return true;
        }
        if (o instanceof Employee){
            Employee e = (Employee) o;
            if (e.num.equals(this.num) && e.name.equals(this.name))
            {
                return true;
            }
        }
        return false;
    }
    //重写Hashcode方法
    public int hashCode(){
        //以员工编号分组,可散列均匀分布
        return num.hashCode();
    }
}

hashCode()的底层实现:

    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;
    }

可以看到最终hash = s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1];
1.选用的哈希函数

哈希函数的目的就是为了产生譬如字符串的哈希值,让不同的字符串尽量产生不同的哈希值的函数就是好的哈希函数,完全不会产生相同的哈希函数就是完美的。

2.处理冲突的方法

处理冲突的方法有多种,拉链法、线性探测等,我喜欢用拉链法

3.哈希表的大小

这个哈希表的大小是固定的,但可以动态调整,也就是创建个新的数组,用旧的给新的循环重新计算Key赋值,删除旧的。但最好根据需求数据量设置足够大的初始值,防止动态调整的频繁,因为调整是很费时又费空间的。还有重要的是,这个哈希表的大小要设为一个质数,为什么是质数?因为质数只有1和它本身两个约数,当用bkdrhash算得的key对哈希表大小取余时,不会因为存在公约数而缩小余数的范围,如果余数范围缩小的话,就会加大碰撞的几率(说法有点牵强,知道的童鞋请给个合理的解释)。

4.装载因子,即哈希表的饱和程度


image

一般来说装载因子越小越好,装载因子越小,碰撞也就越小,哈希表的速度就会越快,可是这样会大大的浪费空间,假如装载因子为0.1,那么哈希表只有10%的空间被真正利用,其余的90%都浪费了,这就是时间和空间的矛盾点,为了平衡,现在大部分采用的是0.75作为装载因子,装载因子达到0.75,那么就动态增加哈希表的大小。

相关文章

  • equals和==分析

    基本概念 在 Java中 ==是运算符,比较的是两个变量是否相等;equals()是Object方法,用于比较两个...

  • 搞懂 Java equals 和 hashCode 方法

    搞懂 Java equals 和 hashCode 方法 分析完 Java List 容器的源码后,本来想直接进入...

  • Java 比较相等

    Java Equals() 特性 Equals() 和 == 的区别 重写Equals方法 重写HashCode方法

  • equals,==和 equals,hashCode

    == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引...

  • equals 与 hashCode 笔记三

    第三篇文章主要讲解相关“ equals 与 == ”面试题分析,分为以下部分: String类的“ equals ...

  • Object的基本方法

    一 equals和hashCode equals和== equals的默认实现就是==,既比较两个对象的引用。 最...

  • 【面试1】

    基础 1、equals和==(equals和==的区别)equals:是Object的一个方法,实现对象的比较;复...

  • java容器

    equals和hashCode equals和hashcode间的关系:如果两个对象相同(即equals比较返回t...

  • Java

    equals和hashcode public boolean equals(Object obj){ retur...

  • ==和equals

    在初学Java时,可能会经常碰到下面的代码: 1String str1 =newString("hello");2...

网友评论

本文标题:equals和==分析

本文链接:https://www.haomeiwen.com/subject/njxwcftx.html