代码预热
先来看一段代码:
public class Main {
public static void main(String[] args) {
Person person1 = new Person("小明", 10);
Person person2 = new Person("小张", 20);
if (person1.equals(person2)) {
System.out.print("小明其实就是小张");
} else {
System.out.print("他们是两个人");
}
}
}
答应出来的结果是:
他们是两个人
这里可以看出他们对比出来的不是同一个对象
源码分析
走到equals里面看源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
这里采用的是==号,
" == "操作符主要比较的是操作符两端对象的内存地址。如果两个对象的内存地址是一致的,那么就返回 true ;反之,则返回false
8中基本数据类型分别为byte,short,int,long,float,double,char,boolean除了 float 和 double 外,其他使用 == 进行数值比较
看到这里应该能明白上边的等号其实就是一组数值的比较,但是明明是两个对象哪里来的数值进行比较的呢?其实不然:
当对象用 == 进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个 对象,他们的比较后的结果为 true,否则比较后结果为 false
java中所有的类都是继承于一个基类Object,这个基类里面就有这个equals方法,这个方法就是来提供对比两个对象的地址信息的
对象的hashCode
先看一段代码:
public class Main {
public static void main(String[] args) {
Person person1 = new Person("小明", 10);
Person person2 = new Person("小张", 20);
int hash1=person1.hashCode();
int hash2=person2.hashCode();
if (hash1==hash2) {
System.out.print("小明其实就是小张");
} else {
System.out.print("他们是两个人");
}
}
}
结果如下:
他们是两个人
简要说明:这里因为hash1不等于hash2所以两个对象肯定不相等所以返回如上结果,但是这个如果相等的话是不是就说明两个对象是同一个对象呢?答案是:不一定
其中hashCode的源码如下:
@HotSpotIntrinsicCandidate
public native int hashCode();
native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
他是一个本地的方法并且返回一个int型的数,但是这个是不是就是对象在内存中的地址呢?我们再看下面一段代码:
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = s1+s2;
System.out.println(s3==s4);
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println(System.identityHashCode(s3));
System.out.println(System.identityHashCode(s4));
}
}
结果是这样的:
false
-1524582912
-1524582912
2088051243
1277181601
因为s3==s4返回的是一个false说明他们在内存中的地址是不一样的不是同一个对象。但是他们的hashcode返回的数值却是一样的,这就说明了hashcode并不是内存中的实际地址,要想获得内存中的地址必须使用System.identityHashCode来获取。但是hashcode是什么呢?我们继续往下分析
hashCode的作用
官方文档对hashcode的定义是这样的
hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上equals比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。如果根据equals(Object)方法,两个对象是相等的,那么在两个对象中的每个对象上调用hashCode方法都必须生成相同的整数结果。 以下情况不 是必需的:如果根据equals(java.lang.Object)方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是Java编程语言不需要这种实现技巧。)
感谢理解Java中hashCode的作用一文。
其实这里可以这样理解,以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样
- new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。
- 比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal
总结
到这里我们再来看上边的代码可以总结出:
- 当我们用equals时比较的是两个对象的实际地址,这个很精确的可以判断出两个对象是不是同一个对象
- 当我们使用==号时比较的是数值是否相同
- 当我们使用hashcode的时候比较的是两个对象在hash表中计算出来的位置,当两个hashcode相同的时候并不能代表是同一个对象,两个不同的对象计算出来的hashcode可以相同,简称hash冲突,这个时候需要对比是否相同还是需要使用equals,但是不相同的时候肯定不是同一个对象,利用hashcode是为了提高了取对象的效率!









网友评论