❤️作者主页:小虚竹
❤️作者简介:大家好,我是小虚竹。Java领域优质创作者🏆,CSDN博客专家🏆,华为云享专家🏆,掘金年度人气作者🏆,阿里云专家博主🏆
❤️技术活,该赏
❤️点赞 👍 收藏 ⭐再看,养成习惯
PC端左侧加我微信,进社群,有送书等更多活动!
问题
有个粉丝问虚竹哥:为什么内存地址一样,但比较用“==”时,结果是false;
比较用equals()时,得到的结果是true。
分析
虚竹哥刚开始也是一脸懵,使用clone方法 克隆出来的对象是新对象,(深入解析题目:【第33题】JAVA高级技术-对象克隆2(浅克隆))
内存地址怎么可能会一样?
但是粉丝就是截图出来了,有图有真相是吧
难道是我记错了?
我不信!
写个代码验证下:
Address类
packagecom.xiaoxuzhu;/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/publicclassAddress{privateString state;// 表示员工所在的国家privateString province;// 表示员工所在的省privateString city;// 表示员工所在的市publicAddress(String state,String province,String city){// 利用构造方法进行初始化this.state = state;this.province = province;this.city = city;}publicStringgetState(){return state;}publicvoidsetState(String state){this.state = state;}publicStringgetProvince(){return province;}publicvoidsetProvince(String province){this.province = province;}publicStringgetCity(){return city;}publicvoidsetCity(String city){this.city = city;}@OverridepublicStringtoString(){// 重写toString()方法StringBuilder sb =newStringBuilder();
sb.append("国家:"+ state +", ");
sb.append("省:"+ province +", ");
sb.append("市:"+ city);return sb.toString();}}
Employee类:
packagecom.xiaoxuzhu;/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/publicclassEmployeeimplementsCloneable{privateString name;// 表示员工的姓名privateint age;// 表示员工的年龄privateAddress address;// 表示员工的地址publicEmployee(String name,int age,Address address){// 利用构造方法进行初始化this.name = name;this.age = age;this.address = address;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicAddressgetAddress(){return address;}publicvoidsetAddress(Address address){this.address = address;}@OverridepublicEmployeeclone(){// 实现浅克隆Employee employee =null;try{
employee =(Employee)super.clone();}catch(CloneNotSupportedException e){
e.printStackTrace();}return employee;}}
再写个测试类:
packagecom.xiaoxuzhu;/**
* Description:
*
* @author zenghw
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/8/23.1 zenghw 2022/8/23 Create
* </pre>
* @date 2022/8/23
*/publicclassTest{publicstaticvoidmain(String[] args){Address address =newAddress("中国","福建","厦门");// 创建address对象Employee employee1 =newEmployee("小虚竹",30, address);// 创建employee1对象Employee employee2 = employee1.clone();System.out.println(employee1);System.out.println(employee2);System.out.println(employee1 == employee2);}}
clone克隆后的对象,内存地址是不一样的。虚竹哥拍了拍胸膛,安心了。
但为什么粉丝得到了内存地址一样的对象呢?
经常虚竹哥跟粉丝的沟通,终于找到问题了
问题出在重写了equals方法,也重写了hashCode方法。
在打印对象时,发生了什么?可以来分析下
System.out.println(employee1);
首先是调用PrintStream.println 方法,方法里对要打印的对象进行转化成字符串。
String.valueOf 方法对入参对象进行判空处理,如果为null时,返回字符串“null”。如果不是null,则调用对象的toString() 方法。
一开始对Employee类 没有重写toString() 方法。 所以这里会进入Object对象 的toString() 方法。
打印的是employee1对象所继承的Object类中的hashCode方法返回的值。
但我们发现这个对象已经是native了,至于Object 的hashCode方法是如何取值的,大家可自行去看下源码,如何看源码传送门。
可知:不同的对象产生的hashCode是不同的;默认情况下,对象的hashCode是通过将该对象的内部地址转换成一个整数来实现的。
好了,分析了这么多,回到粉丝的问题上来:
问题出在重写了equals方法,也重写了hashCode方法。
因为粉丝把hashCode方法重写了,导致得到的hashCode值并不代表着内存地址了。
System.out.println(employee1 == employee2);
这里是内存地址的比较
才会让人有一种错觉!内存地址(输出)明明一样,用比较“==”得到了false。
四、推荐专栏
《JAVA从零到壹》
《JAVA筑基100例》
我是虚竹哥,我们下期见~~~
版权归原作者 小虚竹 所有, 如有侵权,请联系我们删除。