== ,比较的是两个引用对象是否指向同一块内存
equals ,比较的是两个字符串的值是否相等
一、 equals 和 ==区别:
1. 判断两个String对象是否相等
当我们通过new关键字来创建对象时,就会在堆里面分配一块空间。
代码块:
public class Test {
public static void main(String[] args) {
String str1 = new String("123");
String str2 = new String("123");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
}
}
内存图:
代码运行结果:
因为这两个引用对象str1,str2引用的是不同的两块内存,所以==比较结果为false。
由于默认继承于Object类的equals方法,但是String类重写了equals方法,String比较的是两个字符串的值是否相等,与内存地址是否相等没关系,而字符串str1和str2的值都是123,所以为true。
结论:
== 比较,比较的是两个引用对象是否指向同一块内存
equals 比较,比较的是两个字符串的值是否相等
2. 判断两个自定义对象是否相等
代码块:
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = new Person(1,"S");
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
代码运行结果:
2.1 详解:
System.out.println(p1 == p2);
== 比较的是两块引用所指向的内存地址,显然通过new来创建的两个对象在内存中会分配两块内存空间,所以为 false.
对于equals方法,因为默认继承于Object的equals方法,而Person类中并没有重写equals方法,所以当比较p1.equals(p2))时,通过调用Object类中的equals方法来进行比较,而Object类中的equals方法比较是通过内存地址来比较的,就是说内存地址相等(p1==p2),则equals为true,反之为false。
显然p1与p2的内存地址不相等,则为false。
所以一般我们都会重写equals()方法(重写代码下面有详解)
注意: 这里可能会对内存地址和hashCode概念有所混淆
即使重写hashCode方法,使得hashcode值相等,但是p1与p2的内存地址任然不相等,比较的是内存地址,不是hashCode值是否相等,有关内存地址与hashCode关系下面有简单提到。
所以当我重写hashCode()方法,并使得返回的值相等,p1.equals(p2))的值仍然为false。举例说明:
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = new Person(1,"S");
System.out.println(p1 == p2); // false
System.out.println(p1.hashCode()+","+p2.hashCode()); // 1,1
System.out.println(p1.equals(p2)); // false
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
return 1;
}
}
运行结果:
false
1,1
false
2.2 重写equals()方法:
equals()方法我们一般不使用继承自Object类来判断,而是通过IDEA工具来生成已经@Override 的equals()方法。
当此equals()方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
hashCode()方法我们一般不使用Object类的,而是通过IDEA工具来生成已经@Override 的方法。
代码块:
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = new Person(1,"S");
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
代码详解:
if (this == obj)
return true;
== 比较的是两个引用对象是否指向同一块内存,显然p1和p2引用的是两块内存空间,所以return false;
if (obj == null) return false;
当传入的参数对象 obj 为null,则一定为false。
if (getClass() != obj.getClass()) return false;
当两个对象不是一个Class,则为false。
Person other = (Person) obj;
当上个条件getClass() != obj.getClass() 不满足,即属于同一个Class时,把obj的类型Object转化为Person类型
if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true;
通过转化为Person后,对属性进行比较。相等则为true,反之为false
二、 HashCode 和 内存地址 关系:
如果没有人为的修改生成的HashCode值,那么 可以理解 HashCode 是内存地址,或者可以说HashCode就是内存地址。
但是 当重写HashCode方法,并修改了HashCode值后,此时内存地址不能理解为HashCode了。
来自生活的例子理解:
要想找到刘德华住在哪里,可以通过以下两种来找。
一、住在上海浦东新区纳贤路799号(相当于内存地址),二、上海浦东新区益江小区第三排第二列的5楼(相当于hashcode)。
同理要想找到黄日华住在哪里,可以通过以下两种来找。
一、住在上海浦东新区纳贤路600号(相当于内存地址),二、上海浦东新区益江小区第三排第一列的3楼(相当于hashcode)。
当我们想要找刘德华时,可以通过上海浦东新区益江小区第三排第二列的5楼(相等于hashcode)对应上海浦东新区纳贤路799号(相当于内存地址),从而找到刘德华这个人。此时可以理解为内存地址是hashcode。
但是当我们修改上海浦东新区益江小区第三排第二列的5楼(相当于hashcode) 为上海浦东新区益江小区第三排。修改上海浦东新区益江小区第三排第一列的3楼(相当于hashcode) 为上海浦东新区益江小区第三排,并没有具体的详细的地址,此时,黄日华和刘德华的hashcode相等,但是他们的内存地址不相等。所以此时,不能理解为内存地址是hashcode。
代码举例: 不修改hashCode()方法,默认调用Object类的hashCode()方法
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = new Person(1,"S");
System.out.println(p1 == p2);
System.out.println(p1.hashCode()+","+p2.hashCode());
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
运行结果:
false
1704856573,705927765
(因为分配了两块内存)内存地址不相等,HashCode值不相等
但是当我重写HashCode方法,并使得返回的哈希码值相等,此时内存地址不能理解为HashCode了。
举例:
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = new Person(1,"S");
System.out.println(p1 == p2); // false
System.out.println(p1.hashCode()+","+p2.hashCode()); //值相等
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
return 1;
}
}
运行结果:
false
1,1
但是两个对象引用同一块内存地址,引用同一个对象时,此时内存地址相等,hashcode值也相等
举例:
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1,"S");
Person p2 = p1;
System.out.println(p1 == p2); // true
System.out.println(p1.hashCode()+","+p2.hashCode()); //值相等
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
运行结果:
true
1704856573,1704856573