通常在面试中会被问到equals方法和==的区别,以及有没有重写过equals方法,以及重写equals方法的约定是什么? 下面简单的介绍一下我的理解: 首先,在比较基本类型中==和equals方法没有任何区别。 但是在比较引用类型,如对象中 equals 是通常是比较的是对象的实例是否相同。 ==通常是比较的是对象的实例的地址是否相同即对象实例的id。这是两个最重要的区别。 其次,重写equals方法的原则或者说约定是什么,以及什么时候应该覆盖equals呢 如果类具有自己特有的“逻辑相等”概念(不等同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这个时候我们要覆盖equals方法(通常属于值类的情况)。—来自于effective Java 中文版 但是在覆盖equals方法的时候要遵守的约定如下: equals方法实现了等价的关系 1.自反性。对于任何非null的引用值x,x.equals(x)都必须返回true 2.对称性。对于任何非null的引用值x和y,当且仅当x.equals(y)返回true的时候,y.equals(x)也必须返回true 3.传递性。对于任何非null的引用值x,y和z,如果x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)也必须返回true。 4.一致性。对应任何非null的引用值x,y,只要equals比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致性的返回true或者一致性的返回false。—–来自于effective Java 中文版
由一个例子引出的四个方面谈一谈经典的==和equals的问题
代码:
private staticvoid test(){
String a =“a”+”b”+1;
String b =“ab1”;
System.out.println(a==b);
}
关于这一段程序会输出的结果是什么?你可能会说是true或者false,那真正的答案是true;我们从下面4
个方面来分析这个问题
1. 关于“==”是干什么的?
1.1 关于“==”
首先要知道“==”用于匹配内存单元上的内容,其实就是一个数字,计算机内部也只有数字。在java中,
当“==”匹配的时候,其实就是对比两个内存单元的内容是否一样。
如果是原始类型byte、boolean、short、char、int、float、double等就是直接比较他们的值。
如果是引用(reference),比较的是引用的值,可以被认为是对象的逻辑地址。如果两个引用使用“==
”比较操作,就是比较行营的两个对象的地址是否一样。如果一样则返回true,否则返回false。
2. 关于equals是干什么的?
2.1关于“equals”
说起equals方法,大家都不陌生,是在Object类中被定义的,他的定义就是默认使用“==”来匹配的。也
就是说如果我们不重写equals方法,并且对应的父类中也都没有重写过equals,可以默认为是用equals使
用的是比较对象的地址是否相同。
而equals之所以存在,是希望用户的子类去重写这个方法,实现对比值的功能。类似的String就实现了
equals方法。自己去实现这个方法是因为当我们两个对象对比时只选取其中关键的业务属性上面来。确定
他们是否是“一致的或者是相似的”,则返回true/false即可。
注:相似的理解
有时我们在一个情景业务条件下,并不一定需要绝对相同才可以认定为相同,比如我们都知道我们的亲子
鉴定的结果,出来都没有100%的可能性,那现在就要发挥这个相似的作用了,我们可以规定只要他的报告
相似度为98%以上,我就认为是亲生的即(返回true否则返回false)。也就是说,两个对象的值是否相等
是自己的业务来决定的而不是java语言本身所决定的。
3. a和b在内存中是如何分配的(是怎样的)?
回到页首的例子中,其中等号说明a和b是指向同一块内存空间的,就想两个人拿到同一个公司的offer一
样,所有答案才是true;
4. jvm在编译阶段的优化方案
a引用是通过“+”赋值的,b引用是直接赋值的,那为什么a和b会共享一个内存单元?这就是jvm的“编译
时优化”。
当我们的编译器在编译代码String a = “a”+”b”+1,时会将其编译为String a =”ab1”;因为他们都
是常量,编译器认为这3个常量的叠加会达到固定的值,无需运行时候进行技算,所有就会这样优化。
这样做的目的是我们把同样的业务逻辑放在一起执行,更能解决资源的均衡和辉煌。