equals ()与 hashcode() 与 == 解析


  在Object类中有equals与hashCode的实现,在Object类中 equals(Object o) 与 ”==“ 具有 相同的作用效果。为hashCode呢?是对象引用的内存地址的一种映射,因此也算是唯一的了。如果我们你自己写的类,而不去实现自己的equals()与hashCode() 那么肯定是调用Object的方法。如果调用的是Object的实现 那么我们写个类来测试一下。

class Student {
		 String name;
		 int clas;
		 public void setName(String name) {
			 this.name = name;
		 }
		 public void setClass(int clas) {
			 this.clas = clas;
		 }
		 public Student(String name, int clas) {
			 this.name = name;
			 this.clas = clas;
		 }
	}
public class Solution {
	public static void main(String args[]) {
		
		Student st = new Student("a",1);
		Student s = st;
		s.setName("b"); 
		System.out.println(s == st);
		// 注意 值已经不一样的了,但是hashCode 没有改变。
		// hashCode 是通过引用的地址映射的
		// st与 s 的引用时相同的 
		System.out.println(st.hashCode());// true
		System.out.println(s.hashCode());
		System.out.println(s.equals(st));// true
	}
}
那么我们看看Java自己的类是如何重写equals 与 hashCode方法的?

1. 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;
    }
我们可以看出,首先比较是不是同一个引用,如果是返回真,如果不是同一个引用那么就比较值是否相等。因为String是final 类型,如果引用相同 那么内容必定相同。

equals 比较就是字符串的实际内容,在String中 == 比较的是引用的地址,就是申请堆的地址。但是由于字符串有可能放在了常量池,什么时候会放到常量池中呢 ?

当我 使用String s = "Java" Java 就会被放到常量池,如果不存在就在池子中创建。

但是如果String s = new String("Java")  这个时候执行器就不会管你什么常量池,它一看是new ,就会在堆中申请一段空间 然后把这段空间的引用返回给s。

总结就是:

String s = "Java" 去常量池里面找,找到了就返回这个引用地址,没找到在常量池中创建。

String s1 = new String("Java") ; 老老实实在堆中申请,返回新的引用地址。


看看String的hashCode的实现

  public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
  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;
    }
看见没有String的hashCode 是怎样生成的!只要字符串的内容相同 则一定产生相同的hashCode值。我才不管是不是同一个引用呢!


2. Integer 类的equals 与 hashCode 方法

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
看得出比较的是内容,即对应的数值是否相等。

再看看hashCode源码实现

  public int hashCode() {
        return value;
    }
hashCode值就是整数值啊。


有很多这样的问题:

问题1:

Integer a = 1;

int b = 1; 

a == b 

一个是基本数据类型另一个是对象 比较结果为什么是true ?

这是由于java的一个机制 "自动装箱" 与"自动拆箱" 这里就是自动拆箱。Integer类就是这样一个箱子,如果和基本类型数据比较 Integer这个大箱子 就会把 数取出来再和 b进行比较 因此。 1 == 1 必定是真的。


问题2

Integer a = 1;

Integer b = 1;

a == b // true

你会问 怎么这个也是真? 比较的不是引用的地址么? 这是因为 这样创建的对象是在 常量池中的。 创建a的时候 就会在常量池中 创建a 在创建 b的时候 发现 常量池中已经有1了 就直接返回 引用的地址。因此a,b实际指向的是同一块的内存区域。a == b 自然是true


问题3

Integer a = 128;

Integer b = 128;

a == b //false

为什么这个会是false ? 这和问题2不是差不多么?常量池存储的数据是有范围的 只能存储一个字节的数据(-128~127)超过了范围,对象就不会在常量池中了,而是老老实实的在堆中申请,返回在堆中申请的地址。因此 a与b此时 指向的并不是同一块的内存的区域。也就是为什么 a == b 是 false


问题4

Integer a = new Integer(1);

Integer b = new Integer(1);

a == b // false

这个问题 原因就是 ”new “ 的强大之处。使用new 就是 明确告诉JVM 别跟我玩别的。我就要你 去堆中找一块空地。这块空地谁也不许用。就得给我。 a 与 b 都是各自在堆中找到个地方。 然后这俩地方比必定是不同的。


我们说的hashCode与equals 与==的解析问题,好像没有说明她们的区别与联系。其实关键在于你怎么实现hashCode与equals 。 == 比较的一定是引用。

重写hashCode 实现的时候要遵循下面的协定:

  • 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 
  • 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 
  • 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值