1.equals()方法在Object源码中,比较的是对象地址。
Object中的equals()方法的源码如下:
public boolean equals(Object obj){
return (this == obj);// “==”默认比较地址
}
在子类中覆写equals()方法。
class Person extends Object {// extends Object一般省略,默认继承
// 定义属性Person的属性age
private int age;
// 定义有参构造函数
Person(int age) {
this.age = age;
}
// 对Object中的equals方法进行覆写
public boolean equals(Object obj) {
Person p = (Person) obj;// 由于obj不存在子类的属性age,所以要对obj进行类型强转
return (this.age == p.age);
}
}
demo测试用例。
public class MyEqualsDemo {
public static void main(String[] args) {
Person p1 = new Person(20);
Person p2 = new Person(20);
System.out.println(p1.equals(p2));// 输出:true
}
}
当调用时,传入的对象不为Person类,即不对应,不能进行强转时,需要进行类型判断。
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
public boolean equals(Object obj) {
if (!(obj instanceof Person)) {// 判断传入的obj是否属于Person类,如果不属于Person类,进行类型强转会报错;
// return false;// 如果不属于Person类,返回false,也可以抛出异常信息,查错更方便;
throw new ClassCastException("类型错误");// 抛出类型错误异常,方便查错;
}
Person p = (Person) obj;// 由于obj不存在子类的属性age,所以要对obj进行类型强转
return (this.age == p.age);
}
}
2.hashCode()方法在Object源码中,保存的是对象在内存中的16进制地址值。
Object中的hashCode()源码如下:
public native int hashCode();//通过系统默认的方法计算hashCode;
String类中覆写的hashCode()方法的源码如下:
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31 * h + val[off++];
}
hash = h;
}
return h;
}
在自定义子类中覆写hashCode()方法。
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
public int hashCode() {
return age;// 直接使用年龄作为hashCode
}
}
demo测试用例。
public class MyEqualsDemo {
public static void main(String[] args) {
Person p1 = new Person(20);
Person p2 = new Person(20);
System.out.println(p1.hashCode());// 输出:20
System.out.println(p2.hashCode());// 输出:20
}
}
以上例子只是说明hashCode()函数的原理,实际使用过程中会尽量避免不同对象具有相同的hash值。
一般情况下,不同的对象具有不同的hashCode,但是有时候不同的对象会出现相同的hashCode,这就需要在实际情况中覆写hashCode,以达到不同的对象一定具有不同的hashCode,确保唯一性。
哈希表确定元素是否相同
判断源码如下:
if(this.hashCode()== obj.hashCode() && this.equals(obj))// 判断hashCode和值(假设覆写之后的equals方法是判断值)
判断步骤如下:
- 首先调用hashCode()函数计算两个对象的哈希值(地址),判断的是两个对象的哈希值(地址)是否相同;
- 如果哈希值(地址)相同,再调用equals()方法判断两个对象的内容是否相同;
- 如果内容也相同,则表示为同一个对象,否则,不是同一个对象;
注意:
- 判断哈希值相同,用的是对象的hashCode()的方法。判断内容相同,用的是equals方法。
- 如果哈希值不同,是不需要调用equals判断内容。
补充扩展HashSet:
内部数据结构是哈希表,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。
如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。
一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。
建立对象判断是否相同的依据。
3.toString()方法在Object源码中,是将类名和对象地址进行拼接。
Object中的toString()方法源码如下:
public String toString() {
return (getClass().getName() + '@' + Integer.toHexString(hashCode()));
}
- 注:getClass() 返回此 Object 的运行时类。
demo测试用例直接调用toString()方法。
public class MyEqualsDemo {
public static void main(String[] args) {
Person p = new Person(20);
System.out.println(p);// 输出:myPractice.Person@299a06ac
System.out.println(p.toString());// 输出:myPractice.Person@299a06ac
}
}
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
}
Person类继承了Object类中的toString()方法,所以Person类的对象p具有toStirng()函数。
直接输出p和输出p.toString()方法具有相同的结果,是因为输出p会默认调用toString()方法。
在子类中覆写toSting()方法。
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
public String toString() {
return "Person:" + age;// 任意形式的覆写,只要返回字符串即可
}
}
demo测试用例。
public class MyEqualsDemo {
public static void main(String[] args) {
Person p = new Person(20);
System.out.println(p);// 输出:Person:20
System.out.println(p.toString());// 输出:Person:20
}
}
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
public String toString() {
return "Person:" + age;
}
}
以上例子可知,覆写toSting()方法之后,Person类的对象p的值改变了。
4.总结
一般情况下,会对类中的equals()方法、hashCode()方法、toString()方法进行重写。
完整demo测试用例如下:
public class MyEqualsDemo {
public static void main(String[] args) {
Person p1 = new Person(20);
Person p2 = new Person(20);
System.out.println(p1.equals(p2));// 输出:true
System.out.println(p1.hashCode());// 输出:20
System.out.println(p2.hashCode());// 输出:20
System.out.println(p1);// 输出:Person:20
System.out.println(p1.toString());// 输出:Person:20
}
}
class Person extends Object {// extends Object一般省略,默认继承
private int age;
Person(int age) {
this.age = age;
}
public boolean equals(Object obj) {
if (!(obj instanceof Person)) {// 判断传入的obj是否属于Person类,如果不属于Person类,进行类型强转会报错;
// return false;// 如果不属于Person类,返回false,也可以抛出异常信息,查错更方便;
throw new ClassCastException("类型错误");// 抛出类型错误异常,方便查错;
}
Person p = (Person) obj;// 由于obj不存在子类的属性age,所以要对obj进行类型强转
return (this.age == p.age);
}
public int hashCode() {
return age;// 直接使用年龄作为hashCode,
}
public String toString() {
return "Person:" + age;
}
}