Java覆写equals()方法、hashCode()方法、toString()方法原理解析

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方法是判断值)

判断步骤如下:

  1. 首先调用hashCode()函数计算两个对象的哈希值(地址),判断的是两个对象的哈希值(地址)是否相同;
  2. 如果哈希值(地址)相同,再调用equals()方法判断两个对象的内容是否相同;
  3. 如果内容也相同,则表示为同一个对象,否则,不是同一个对象;

注意:

  • 判断哈希值相同,用的是对象的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;
	}
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值