0
点赞
收藏
分享

微信扫一扫

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)


❤️作者主页:​​小虚竹​​


PC端左侧加我微信,进社群,有送书等更多活动!

问题

有个粉丝问虚竹哥:为什么内存地址一样,但比较用“==”时,结果是false;

比较用equals()时,得到的结果是true。

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_java

分析

虚竹哥刚开始也是一脸懵,使用clone方法 克隆出来的对象是新对象,(深入解析题目:【第33题】JAVA高级技术-对象克隆2(浅克隆))
内存地址怎么可能会一样?
但是粉丝就是截图出来了,有图有真相是吧
难道是我记错了?
我不信!
写个代码验证下:
Address类

package com.xiaoxuzhu;

/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/
public class Address {
private String state; // 表示员工所在的国家
private String province;// 表示员工所在的省
private String city; // 表示员工所在的市

public Address(String state, String province, String city) {// 利用构造方法进行初始化
this.state = state;
this.province = province;
this.city = city;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}

public String getProvince() {
return province;
}

public void setProvince(String province) {
this.province = province;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

@Override
public String toString() {// 重写toString()方法
StringBuilder sb = new StringBuilder();
sb.append("国家:" + state + ", ");
sb.append("省:" + province + ", ");
sb.append("市:" + city);
return sb.toString();
}
}

Employee类:

package com.xiaoxuzhu;

/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/
public class Employee implements Cloneable {
private String name; // 表示员工的姓名
private int age; // 表示员工的年龄
private Address address;// 表示员工的地址

public Employee(String name, int age, Address address) {// 利用构造方法进行初始化
this.name = name;
this.age = age;
this.address = address;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

@Override
public Employee clone() {// 实现浅克隆
Employee employee = null;
try {
employee = (Employee) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return employee;
}
}

再写个测试类:

package com.xiaoxuzhu;

/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/
public class Test {
public static void main(String[] args) {
Address address = new Address("中国", "福建", "厦门");// 创建address对象
Employee employee1 = new Employee("小虚竹", 30, address);// 创建employee1对象
Employee employee2 = employee1.clone();
System.out.println(employee1);
System.out.println(employee2);
System.out.println(employee1 == employee2);
}

}

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_hashCode_02


clone克隆后的对象,内存地址是不一样的。虚竹哥拍了拍胸膛,安心了。

但为什么粉丝得到了内存地址一样的对象呢?

经常虚竹哥跟粉丝的沟通,终于找到问题了

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_初始化_03


问题出在重写了equals方法,也重写了hashCode方法。

在打印对象时,发生了什么?可以来分析下

System.out.println(employee1);

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_hashCode_04


首先是调用PrintStream.println 方法,方法里对要打印的对象进行转化成字符串。

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_开发语言_05


String.valueOf 方法对入参对象进行判空处理,如果为null时,返回字符串“null”。如果不是null,则调用对象的toString() 方法。

一开始对Employee类 没有重写toString() 方法。 所以这里会进入Object对象toString() 方法。

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_hashCode_06

打印的是employee1对象所继承的Object类中的hashCode方法返回的值。

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_初始化_07


但我们发现这个对象已经是native了,至于Object 的hashCode方法是如何取值的,大家可自行去看下源码,​​如何看源码传送门​​。

可知:不同的对象产生的hashCode是不同的;默认情况下,对象的hashCode是通过将该对象的内部地址转换成一个整数来实现的。

好了,分析了这么多,回到粉丝的问题上来:

猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)_初始化_03


问题出在重写了equals方法,也重写了hashCode方法。

因为粉丝把hashCode方法重写了,导致得到的hashCode值并不代表着内存地址了。

System.out.println(employee1 == employee2);
这里是内存地址的比较

才会让人有一种错觉!内存地址(输出)明明一样,用比较“==”得到了false。


举报

相关推荐

0 条评论