1. "=="与equals()的比较
== 运算符:
- 可以使用在基本数据类型和引用数据类型变量中
- 比较基本数据类型变量,比较保存的实际是否相等 (类型不一定要相同)
- 比较引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个地址
使用:
int a = 10;
int b = 10;
double c = 10.0;
float d = 7;
System.out.println(a==b); // true
System.out.println(b==c); // true
System.out.println(c==d); // false
equals():
- equals()是一个方法,而非运算符
- 适用于引用数据类型
- object中定义的equals方法和"=="的作用是相同的
- String Date File 包装类等都重写了Object类中的equals方法。重写后,比较的是两个对象的实体内容是否相同。
- 通常情况下,需要在自定义类中对equals方法进行重新操作去判断实体内容是否相同
自反性 :对于任何非空的参考值x , x.equals(x)应返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应返回true当且仅当y.equals(x)回报true 。
传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true倍y.equals(z)的返回true ,然后x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false (前提是未修改在对象的equals比较中使用的信息)。
对于任何非空的参考值x , x.equals(null)应返回false 。
String str1 = "ABC123";
String str2 = "ABC123";
System.out.println(str1==str2); // true
equals()源码:
public boolean equals(Object obj) {
return (this == obj);
}
2. 重写equals()方法
首先,看一下不进行equals()重写的比较情况:
// 定义学生类,属性为姓名、年龄
class Student{
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Student stu1 = new Student("stu",18);
Student stu2 = new Student("stu",18);
System.out.println(stu1==stu2); // false
System.out.println(stu1.equals(stu2)); // false
stu1和stu2的姓名、年龄均相同,这时候"=="比较的是二者的地址值,为false;equals底层使用的也是这个运算符,所以也为false。
下面在Student类中对equals()进行重写:
重写方法由idea(Alt+Insert)自动生成,判断对象内容是否相等。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return Objects.equals(name, student.name);
}
//测试
Student stu1 = new Student("stu",18);
Student stu2 = new Student("stu",18);
System.out.println(stu1==stu2); // false
System.out.println(stu1.equals(stu2)); // true
注意点:
- 重写equals()方法之后,为遵循相等的对象必须有相等的hashCode值,所以也要进一步对hashCode()进行重写。
3. hashCode()介绍
百科介绍:
hash code是一种编码方式,在Java中,每个对象都会有一个hashCode,Java可以通过这个hashcode来识别一个对象。至于hashcode的具体编码方式,比较复杂(事实上这个编码是可以由程序员通过继承和接口的实现重写的),可以参考数据结构书籍。而hashtable等结构,就是通过这个哈希实现快速查找键对象。这是他们的内部联系,但一般编程时无需了解这些,只要知道hashtable实现了一种无顺序的元素排列就可以了。.
注意点:
- 对象相等则hashCode一定相等;
- hashCode相等对象未必相等。
应用上述Student类举例:
- 在未重写hashCode()时,即使两个对象stu1和stu2的属性相同,因为他们的内存地址不同,所以产生的hashCode也不相同。
重写hashCode():
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
- 当Student类对equals()进行重写后,为保证相等的对象必须有相等的hashCode值,因此也要对hashCode()进行重写,重新生成hashCode值。
//相等时,具有相同的hashCode值
System.out.println(stu1.hashCode()); // 3541086
System.out.println(stu2.hashCode()); // 3541086
注意: 当两个对象相等时,他们的hashCode一定相等;但当hashCode相等时,如果未重写hashCode(),那么hashCode相同即两对象指向了同一地址,但如果hashCode()重写后,hashCode相同两对象就未必会指向同一地址,因此,判断两个对象是否是指向同一地址,不能依靠类中的hashCode方法。
以上述Student类举例:
// 未重写hashCode()
Student stu1 = new Student("stu",18);
Student stu2 = new Student("stu",18);
Student stu3 = stu1;
System.out.println(stu1.hashCode()); // 1831932724 --> 指向同一地址
System.out.println(stu2.hashCode()); // 1747585824
System.out.println(stu3.hashCode()); // 1831932724 --> 指向同一地址
//用"=="判断是否为同一地址
System.out.println(stu1==stu2); // false
System.out.println(stu1==stu3); // true
//重写了hashCode()
Student stu1 = new Student("stu",18);
Student stu2 = new Student("stu",18);
Student stu3 = stu1;
System.out.println(stu1.hashCode()); // 3541086 --> 指向同一地址
System.out.println(stu2.hashCode()); // 3541086 --> hashCode相同,地址不同
System.out.println(stu3.hashCode()); // 3541086 --> 指向同一地址
//用"=="判断是否为同一地址
System.out.println(stu1==stu2); // false
System.out.println(stu1==stu3); // true
如何获取对象的真实hashCode,而不受hashCode()方法被覆盖的影响?
public static int identityHashCode( Object x)
无论给定对象的类是否覆盖hashCode(),都为给定对象返回与默认方法hashCode()返回的哈希码相同的哈希码。 空引用的哈希码为零。
举例:在hashCode相同下判断两对象是否指向同一地址:
Student stu1 = new Student("stu",18);
Student stu2 = new Student("stu",18);
System.out.println(stu1.hashCode()); // 3541086
System.out.println(stu2.hashCode()); // 3541086
System.out.println(System.identityHashCode(stu1)); // 1831932724
System.out.println(System.identityHashCode(stu2)); // 1747585824
System.out.println(stu1==stu2); // false
——————END-2022-06-18——————