JAVA知识点回顾之HashCode、Equals和==

1. 运算符 ==

在Java中数据类型分为两大类:基本数据类型(byte,short,char,int,long,float,double,boolean)和引用数据类型(类、接口和数组)。

  • 基本数据类型
    在基本数据类型中,== 操作比较的是两个变量的是否相等。
  • 引用数据类型
    在引用数据类型中,== 操作比较的是两个对象在内存中的引用地址。引用类型在栈中存放的是对象引用(地址),对象是放在堆中。

2. Equals 方法

equals 是 Object类默认提供的方法。

  • 没有覆盖情况
    主要用于判断对象的内存地址是不是同一个地址(是不是同一个对象)
// Object 类equals 源码
public boolean equals(Object obj) {
    return (this == obj);
    }
  • 覆盖情况
    要是覆盖equals方法情况下,则根据具体的代码来确定equals方法的作用。一般都是通过对象的内容是否相等来判断对象是否相等
// String 类 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;
    }
判断相等的步骤:
1. 比较两个String对象是否为同一对象,如果是就直接返回true
2. 如果不是同一对象,先确定传入的对象是否是String类型,如果是,则比较两对象的字符序列
3. 遍历过程中只要有一个字符不相同,就返回false,否则返回true

补充 :覆盖equals需遵守通俗约定

  • 自反性: 对于任何非null的引用值x, x.equals(x)必须返回true
  • 对称性: 对于任何非null的引用值x和y, 当且仅当y.equals(x)返回true时,x.equals(y)必须返回true
  • 传递性: 对于任何非null的引用值x,y,z, 如果x.equals(y)为true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true
  • 一致性: 对于任何非null的引用值x和y, 只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者false
  • 对于任何非null的引用值x, x.equals(null)必须返回false

3.HashCode

hashCode方法返回值是Int型数据,这个值称为哈希码(散列码)。作用:确定该对象在散列表中的索引位置。

  // Object 类的源码
  public native int hashCode();
应用

在Java里集合可以存储大量的数据,那么Set集合中元素是无序且不可重复的,那么Set集合如何来保证元素不重复呢?通过迭代来 equals() 是否相等。数据量小还可以接受,当我们的数据量大的时候效率可想而知。hashCode 提供了解决方案。

hashCode是一个本地方法,它的实现与本地机器有关。当我们向一个集合中添加某个元素,集合会首先调用 hashCode 方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用 equals 方法来匹配这两个元素是否相同,相同则不存,不同则散列到其他位置。这样处理,当我们存入大量元素时就可以大大减少调用 equals() 方法的次数,极大地提高了效率。

hashCode 方法和equals 方法关系

Java 中,当用到HashMap、HashSet、HashTable这类的集合框架时,比如,将自己新建的类作为 HashMap 的 key。这种情况下,需要重写hashCode和equals方法
例子

public class EqHashCode {

	public static void main(String[] args) {
		Student stu=new Student("小米","一班");
		Student stu1=new Student("小米","一班");

		HashMap<Student, String> hashMap = new HashMap<>();
		hashMap.put(stu,stu.className);
		hashMap.put(stu1,stu1.className);

		System.out.println(hashMap.size());
		System.out.println(stu==stu1);
		System.out.println(stu.equals(stu1));
	}

}

public class Student {
	public String name;
	public String className;

	public Student(String name, String className) {
		super();
		this.name = name;
		this.className = className;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj instanceof Student) {
			Student stu = (Student) obj;
			if (name.equals(stu.name) && className.equals(stu.className)) {
				return true;
			}
		}

		return false;
	}

	@Override
	public int hashCode() {
		int result = 17;// 非0 任选
		result = 31 * result + name.hashCode();
		result = 31 * result + className.hashCode();
		return result;
	}

}
运行结果:
第一次equals 方法没有覆盖情况下,hashMap size为2;第二次覆盖equals 方法下,hashMap size为1
总结
  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 如果两个对象相等,则两个对象分别调用equals方法都返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 类的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

参考
你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?

你可能感兴趣的:(Java语言)