咱们很方便的定义一个java POJO类,用来表示一个复杂对象。这个对象可能包含一些基本类型的数据成员。好比下面的例子: java
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里面,来方便使用。 ide
List<Info> lists = getInfos();
接下来,有人就会这样使用这个List: this
Info info = new Info("xxx", "yyy", 1); lists.remove(info);
运气很差,移交给QA以后,问题出现了,info对象还在。 code
这个问题说开了一点都不复杂,可是在一个复杂的系统中由于这样的小问题致使出现的bug,排查起来很让人烦心。 对象
抛开原理不谈,咱们就看看java ArrayList是怎么实现remove(Object obj)。 element
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])。 rem
Info对象没有实现equals和hashCode。 get
按照java的标准写法,equals和hashCode要写不少代码。这里咱们用Guava来简化这个工做。 hash
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); } }
简单多了。 ast