一、equals()和==的区别
- ==是基本运算符,用来比较对象的引用是否指向同一块内存地址。
- equals()是一个方法,不可以对8种基本类型进行比较,见源码1,它默认的方法中也使用了==,比较的也是对象的地址。见源码2,只不过equals()可以对其进行重写,像String、Date、Math、File、包装类等大部分类都重写了Object的equals()方法。重写后的equals(),可以把它理解为比较值是否相等。
- 重写equals方法也要重写hashCode,并且遵循五个条件。
源码1. equals是根类Obeject中的方法:
public boolean equals(Object obj) {
return (this == obj);
}
源码2. String类源码中重写的equals方法如下:
public boolean equals(Object anObject) {
// 1. 检查是否为同一个对象的引用,如果是直接返回 true;
if (this == anObject) {
return true;
}
/*2.判断anObject是否为String类的实例,如果不是直接返回false,如果是则取值比较大小。
注:instanceof 测试一个对象是否为一个类的实例
**/
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;
}
二、equals()和==的实战
为什么会出现以下现象?
//1. 比较基本类型
int m=1;
int n=1;
// System.out.println(m.equals(n)); // 报错
System.out.println(m == n); // true
//System.out.println(m.hashCode()); // 报错
//System.out.println(n.hashcode()); // 报错
//2. 比较new出来的封装类型
Integer x = new Integer(1);
Integer y = new Integer(1);
System.out.println(x.equals(y)); // true
System.out.println(x == y); // false
//3. 比较非new封装类型 [-128, 127]
Integer x1 = 127;
Integer y1 = 127;
System.out.println(x1.equals(y1)); // true
System.out.println(x1 == y1); // true
//4. 比较非new封装类型非[-128, 127]
Integer x2 = 128;
Integer y2 = 128;
System.out.println(x2.equals(y2)); // true
System.out.println(x2 == y2); // false
//5. 比较字符串
String s1="abc";
String s2="abc";
System.out.println(s1==s2); // true
System.out.println(s1.equals(s2)); // true
//6. 比较非new字符串常亮
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2)); //true
System.out.println(str1==str2); //false
1. 比较基本类型
对于基本数据类型(byte,short,char,int,float,double,long,boolean)来说,他们是作为常量在方法区中的常量池里面以HashSet策略(HashSet中不允许有重复的元素)存储起来的。因此在常量池,一个常量只会对应一个地址。所以不管是再多的 1,其内存地址都为同一个。
2. 比较new出来的封装类型
new String(“hello”)会在堆内存中创建一个实例,开辟新的内存空间,故==为falsie。但是源码2中,String类源码中重写了equals方法,对单个值的进行比较。
3. 比较非new封装类型 [-128, 127]
4. 比较非new封装类型非[-128, 127]
对于两个非 new 生成的 Integer 对象进行比较时,如果两个变量的值在区间 [-128, 127] 之间,则比较结果为 true,否则为 false。Java 在编译 Integer i = 100 时,会编译成 Integer i = Integer.valueOf(100),而 Integer 类型的 valueOf 的源码如下所示:
public static Integer valueOf(int var0) {
return var0 >= -128 && var0 <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[var0 + 128] : new Integer(var0);
}
从上面的代码中可以看出:Java 对于 [-128, 127] 之间的数会进行缓存,比如:Integer i = 127,会将 127 进行缓存,下次再写 Integer j = 127 的时候,就会直接从缓存中取出,而对于这个区间之外的数就需要 new 了。
5. 比较字符串
在Java执行时会维护一个String池(pool),对于一些可以共享的字符串对象,会先在String池中查找是否存在相同的String内容(字符相同),如果有就直接返回,不创建新对象。
6. 比较非new字符串常量
new String(“hello”)会在堆内存中创建一个实例,开辟新的内存空间,故==为falsie。但是,String类源码中重写了equals方法,对单个值的进行比较。
三、为什么重写equals一定要重写hashcode?: link1,link2
要求:对两个对象,如果equals方法返回true,则hashcode必须也一样!
但是:默认的hashcode方法是根据对象的内存地址经哈希算法得来的,故equals()为true时,两者的hashcode不一定相等。
所以:重写equals一定要重写hashcode