Java中有很多基础的知识,但是也是往往容易被人忽略的,本篇文章主要分析不得不提的==
与equals()
这对冤家(面试基本都会被问到吧)。
== 与 equals()
在java中可以分为值类型与引用类型,8种基本数据类型(byte,short,int,long,float,double,boolean,char)就是属于值类型,其他的都是引用类型(包括我们常用的String)
值类型的比较只能通过==
来进行比较
if(value == 100) {
//do something
}
而引用类型既可以通过==
比较,也可以通过equals()
进行比较,==
比较的是两个对象是否指向同一个地址
A a1 = new A();
A a2 = new A();
A a3 = a1;
Log.v("A", a1 == a2 ? "a1 = a2" : "a1 != a2");
Log.v("A", a1 == a3 ? "a1 = a3" : "a1 != a3");
Log.v("A", a2 == a3 ? "a2 = a3" : "a2 != a3");
输出的结果
a1 != a2
a1 = a3
a2 != a3
a1和a2都是new A(),他们指向的是不同的地址,而a1和a3指向的是同一个地址
那我们接下来修改代码看看equals()的结果是不是一样的
A a1 = new A();
A a2 = new A();
A a3 = a1;
Log.v("A", a1.equals(a2) ? "a1 = a2" : "a1 != a2");
Log.v("A", a1.equals(a3) ? "a1 = a3" : "a1 != a3");
Log.v("A", a2.equals.(a3) ? "a2 = a3" : "a2 != a3");
输出的结果
a1 != a2
a1 = a3
a2 != a3
equals()
的输出结果跟==
是一样的,equals()的实现是在Object里面实现的,看看equals()的源码
public boolean equals(Object o) {
return this == o;
}
也是直接通过==
来进行比较的
既然equals()
的实现直接是通过==
来实现的话,equals()
那存在的意义又是什么呢?先看一个例子
private ArrayList<Hat> mShopHats = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initShopHats();
gotoBuyHat();
}
private void initShopHats() {
mShopHats.add(new Hat("white"));
mShopHats.add(new Hat("black"));
mShopHats.add(new Hat("orange"));
mShopHats.add(new Hat("green"));
mShopHats.add(new Hat("yellow"));
}
private void gotoBuyHat() {
Hat needHat = new Hat("white");
Hat buyHat = buyHat(needHat);
if(buyHat == null) {
Log.i("hat","居然买不到 " + needHat.color + " 帽子");
} else {
Log.i("hat","买到了一顶 " + buyHat.color + " 帽子");
}
}
private Hat buyHat(Hat hat){
for (Hat item: mShopHats) {
if(hat.equals(item)) {
return item;
}
}
return null;
}
public class Hat {
public Hat(String color) {
this.color = color;
}
public String color;
}
上面的代码逻辑大概是这样:首先在mShopHats里面初始化了white、black、orange、green、yellow五种color帽子,然后初始化了一个hat帽子对象,color为white,到商店去买color为white的帽子,再将结果进行打印
I/hat: 居然买不到 white 帽子
商店明明有白帽子,居然告诉我买不到白帽子,这是为什么呢?就是因为equals()
引起的,当我们到商店去买white帽子的时候,程序认为你需要买的帽子是另外一顶white帽子,而不是他们商店里面的那顶white帽子,因此没有买到white帽子。
通过上面的例子,有时候在比较对象的时候,我们只需要比较对象的某些属性相等就认为他们的相等的,就像上面的只要color为white的hat,我们就认为他们是相等的,这恰恰就是equals()
存在的原因。
Java设计equals()
方法其实是交给开发者去覆写的,让开发者自己去定义满足什么条件的两个Object是相等的。若Object没有覆写equals()
,那么调用equals()
就相等于调用==
,比较的是两个对象的地址,更严格地说,没有覆写equals()
而对其进行调用,是一种错误的行为。
对上面的代码进行修改,覆写Hat的equals()
public class Hat {
public Hat(String color) {
this.color = color;
}
public String color;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Hat hat = (Hat) obj;
return color != null ? color.equals(hat.color) : hat.color == null;
}
@Override
public int hashCode() {
return color != null ? color.hashCode() : 0;
}
}
然后再看看执行结果
I/hat: 买到了一顶 white 帽子
通过覆写equals()
,通过比较Hat的color属性来判断两个Hat对象是否相等,终于成功地买到了一顶white帽子了。
在覆写equals()
的同时,我们也覆写了hashCode()
方法,至于为什么要覆写hashCode()以及如何去覆写hashCode(),下一篇会详细介绍。