逻辑运算符(==, !=)比较的是啥?equals()比较的是啥
文章目录
关系运算符
关系运算符会通过产生一个布尔(boolean)结果来表示操作数之间的关系。如果关系为真,则结果为 true,如果关系为假,则结果为 false。关系运算符包括小于 <,大于 >,小于或等于 <=,大于或等于 >=,等于 == 和不等于 !=。
== 和 != 可用于所有基本类型,但其他运算符不能用于基本类型 boolean,因为布尔值只能表示 true 或 false,所以比较它们之间的 “大于” 或 “小于” 没有意义。
== 和 != 测试对象等价
== 和 != 用于比较对象时,比较的是对象引用,即对象在堆中的地址,地址一样则相同。但有个特殊情况
特殊情况
基本数据类型int 的包装类型 Integer 有些特殊。
关系运算符 == 和 != 同样适用于所有对象之间的比较运算,但它们比较的内容却经常困扰 Java 的初学者。下面是代码示例:
// operators/Equivalence.java
public class Equivalence {
public static void main(String[] args) {
Integer n1 = 47;
Integer n2 = 47;
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
}
输出结果:
true
false
表达式 System.out.println(n1 == n2) 将会输出比较的结果。因为两个 Integer对象相同,所以先输出 true,再输出 false。但是,尽管对象的内容一样,对象的引用却不一样。== 和 != 比较的是对象引用,所以输出实际上应该是先输出 false,再输出true。
但它的特殊点就 在于 Integer 内部维护着一个 IntegerCache 的缓存,默认缓存范围是 [-128, 127],这个缓存可以被称为整数缓冲区,假设我们通过Integer创建数据,如果这个数据的范围在-128~127之间,就是直接引用数组cache 中已有的数据。所以 [-128, 127] 之间的 值 用 == 和 != 比较也能能到正确的结果,但是不推荐用关系运算符比较,具体见 JDK 中的 Integer 类源码。
(注:如果你把 47 改成 128,那么打印的结果就是先输出 false,再输出true,因为脱离了整数缓冲区的范围,比较的就是对象引用了)
equals() 方法
equals() 的默认行为也是比较 对象的引用 而非具体内容,只不过一般我们都会重写equals()方法,让其比较内容。
那么怎么比较两个对象的内容是否相同呢? 你必须使用所有对象(不包括基本类型)中都存在的 equals() 方法,下面是如何使用 equals() 方法的示例:
// operators/EqualsMethod.java
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = 47;
Integer n2 = 47;
System.out.println(n1.equals(n2));
}
}
输出结果: true
注意:
上例的结果看起来是我们所期望的。但其实事情并非那么简单。下面我们来创建自己的类:
// operators/EqualsMethod2.java
// 默认的 equals() 方法没有比较内容
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
}
输出结果: false
上例的结果再次令人困惑:结果是 false。
原因:equals() 的默认行为是比较对象的引用而非具体内容。
因此,除非你在新类中覆写 equals() 方法,否则我们将获取不到想要的结果。不幸的是,在学习 复用(Reuse)章节后我们才能接触到 “覆写”(Override),并且直到 附录: 集合主题,才能知道定义 equals() 方法的正确方式,但是现在明白 equals() 行为方式也可能为你节省一些时间。
大多数 Java 库类通过覆写 equals() 方法比较对象的内容而不是其引用。
String类中的equals()方法重写
我们来看一下String类是怎么复写Object.java中的equals()方法的:
private final char value[];
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
我们自己创建一个对象的equals()方法重写
package com.wlw.chapter8_collection;
public class Student {
private String name;
private int age;
@Override
public boolean equals(Object o) {
//1.判断是否为同一对象
if(this == o){
return true;
}
//2.判断是否为空
if(o == null){
return false;
}
//3.判断是否为Student类型
if(o instanceof Student){
//4.类型转换
Student s = (Student) o;
//5.比较内容
if(this.name.equals(s.getName()) && this.age == s.getAge()){
return true;
}
}
// 不满足返回false
return false;
}
}