本文部分内容参考《疯狂Java讲义》
这篇文章其实本来已经写好了的,但是由于官方的设计和本人的疏忽问题,导致被无意间覆盖了,所以今天特地重新写了一份,希望大家在写新博客的时候 如果编辑界面直接显示了上一篇编辑过的论文,那么一定要记得点击写新文章,否则在你编辑发表后会发现你刚编辑的文章已经覆盖了之前的文章,而且是根本恢复不了,所以大家在操作时一定要注意这点,避免不必要的损失。
以后贴程序直接贴图吧,这样看起来更加好看,花花绿绿的比md自带的代码块要好多了。。(话说md写得好以后在申请涨工资的时候能加分吗)
== 和equals方法
Java程序中测试两个变量是否相等有两种方式:一种是利用 == 运算符, 另一种是利用 equals()方法。当使用 == 来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,就将返回true。
但对于两个引用变量类型,只有它们指向同一个对象时, == 才会判断并返回true, == 不可用于比较类型上没有父子关系的两个对象。下面程序是犯了使用== 来判断两种类型变量是否相等的结果。
我们在这里可能会有疑问 , “hello” 直接量和 new String(“hello”)有什么区别?
当Java程序直接使用形如“hello”的字符串直接量(包括可以在编译时就计算出来的字符串值)时,JVM将会使用常量池来管理这些字符串;当使用 new String(“hello”)时,JVM会先使用常量池来管理"hello"直接量,再调用String类的构造器来创建一个新的string对象,新创建的string对象被保存在堆内存中。换句话说,newString(hello)一共产生了两个字符串对象。
常量池(constant pool)专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口中的常量,还包括字符串常量。
JVM常量池保证相同的字符串直接常量只有一个,不会产生多个副本。例子中s1、 s4、s5所引用的字符串可以在编译器就确定下来,因此它们都将引用常量池中的同一个字符串对象。
使用new string()创建的字符串对象是运行时创建出来的,它被保存在运行时内存(既堆内存),不会放入常量池中。
##Object类的equals()方法
所有引用变量都可以调用该方法来判断是否与其他引用变量相等。但使用这个方法判断两个对象相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true。因此这个Object类提供的equals()方法没有太大的实际意义。所以我们如果想用自定义的相等标准我们可以重写它
##String类的equals()方法
String类的equals()方法判断两个字符串相等的标准是:只要两个字符串所包含的字符序列相同,通过equals()比较将返回true。否则将返回false。
#重写equals方法
Object默认提供的quals只是比较对象的地址,和==效果一样,所以我们在实际当中经常要重写equals方法
上面的程序常用写了Person类的equals方法,指定了Person对象和其他兑现相等的标准:另一个对象必须是Person类的实例,且两个Person对象的idStr相等,即可判断两个Person对象相等。在这种判断标准下,可认为只要两个Person对象的身份证字符串相等,即可判断相等。
关于《疯狂java》这本书中 给出了如下equals方法的基本满足条件
- 自反性: 对任意x,x.equals(x)一定返回true
- 对称性:对任意x和y,如果y.equals(x)返回true 则x.equals(y)也返回true
- 传递性:对任意x,y,z,如果x.equals(y)返回true,y.equals(x)返回true 则x.equals(z)也一定返回true
- 一致性:对任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true要么一直是false
- 对任何不适inull的x ,x.equals(null)一定返回false
关于equals方法《Java核心技术》中给出如下建议:
- 显示参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。
- 检测this与otherObject是否引用同一个对象:
if(this == otherObject) return true;
- 这条语句只是一个优化。实际上这是一种经常采用的形式。因为计算这个等式要比一个个的比较类中的域所付出的代价小得多。
- 检测otherObject是否为null,如果为null,返回false。这项检测是很必要的
if(otherObject == null) return false
- 比较this和otherObject是否属于同一个类。如果equals的语义在每个字累中有所改变,就使用getClass方法检测:
if(getClass()! = otherObject.getClass()) return false ;
- 如果所有的子类都拥有统一的语义,就使用 instanceof检测:
if(!(otherObject instanceof ClassName)) return false;
- 将otherObject转换为相应的类类型变量:
ClassName other = (ClassName) otherObject
- 现在开始对所有需要比较的域进行比较了。使用== 比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true;否则返回false。
return field1 == other.field1 && Objects.equals(field2, other.field2) && ...;
- 如果在子类中重新定义equals,就要在其中包含调用super.equals(other)
intanceof运算符
对于intanceof运算符而言,当前面对象是后面类的实例或其子类的实例时都返回true,所以重写equals()方法判断两个对象是否为同一个类的实例时使用instanceof是有问题的。比如这里有个Teacher类型的变量t,如果判断 t instanceof Person, 这也将返回true ,但对于重写equals()方法的要求而言,通常要求两个对象是同一个类的实例,因此使用intanceof运算符不太合适。改为使用t.getClass() == Person.class比较合适。(参考上面代码)