我们很方便的定义一个java POJO类,用来表示一个复杂对象。这个对象可能包含一些基本类型的数据成员。比如下面的例子:
public class Info {
public String uri;
public String name;
public int id;
public Info(String uri, String name, int id) {
this.uri = uri;
this.name = name;
this.id = id;
}
}
接下来,我们有可能会把这种对象存储在List或者Map里面,来方便使用。
List<Info> lists = getInfos();
接下来,有人就会这样使用这个List:
Info info = new Info("xxx", "yyy", 1);
lists.remove(info);
运气不好,移交给QA之后,问题出现了,info对象还在。
这个问题说开了一点都不复杂,但是在一个复杂的系统中因为这样的小问题导致出现的bug,排查起来很让人烦心。
抛开原理不谈,我们就看看java ArrayList是怎么实现remove(Object obj)。
public boolean More ...remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
里面清楚的写着:o.equals(elementData[index])。
Info对象没有实现equals和hashCode。
按照java的标准写法,equals和hashCode要写很多代码。这里我们用Guava来简化这个工作。
public class Info {
public String uri;
public String name;
public int id;
public Info(String uri, String name, int id) {
this.uri = uri;
this.name = name;
this.id = id;
}
@Override
public int hashCode() {
return Objects.hashCode(uri, name, id);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Info other = (Info) obj;
return Objects.equal(this.uri, other.uri)
&& Objects.equal(this.name, other.name)
&& Objects.equal(this.id, other.id);
}
}
简单多了。