ArrayList底层是一个数组,每次加入就是依次向后加入,当删除的时候,比较的是传入的参数是否equals保存在ArrayList中的某个元素,与Hashcode无关,所以一个类如果仅仅重写了equals方法而没有重写hashcode方法,这要两个对象equals返回true,那么就可以成功删除。
HashSet底层是HashMap,根据前面的介绍必须使用hashcode和equals来查找到待删除的元素,所以仅仅重写equals而没有重写hashcode是删除不了的。
Address类首先仅仅重写了equals方法,而没有重写hashcode方法
public class Address
{
private String detail;
public Address(String detail)
{
this.detail = detail;
}
public String getDetail()
{
return detail;
}
public void setDetail(String detail)
{
this.detail = detail;
}
// @Override
// public int hashCode()
// {
// final int prime = 31;
// int result = 1;
// result = prime * result + ((detail == null) ? 0 : detail.hashCode());
// return result;
// }
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (detail == null)
{
if (other.detail != null)
return false;
}
else if (!detail.equals(other.detail))
return false;
return true;
}
}
下面在ArrayList 和HashSet中测试以两个equals的对象,一个加入,然后使用另外一个删除
public static void main(String[] args) throws Throwable
{
Address a1 = new Address("shanghai");
Address a2 = new Address("shanghai");
ArrayList<Address> list = new ArrayList<Address>();
list.add(a1);
list.remove(a2);
//加入a1,然后根据a2删除,能成功删除, list为空
System.out.println(list.isEmpty());
HashSet<Address> set = new HashSet<Address>();
set.add(a1);
set.remove(a2);
//同样的操作在HashSet中就不管用,删除不了,set不为空
System.out.println(set.isEmpty());
}
下面把上面Address类中的重写hashcode方法的注释取消掉,结果是无论ArrayList还是HashCode都能成功删除
在没有重写hashcode的情况下,如果向set中加入两个equals的对象是可以的,例如:
HashSet<Address> set = new HashSet<Address>();
set.add(a1);
set.add(a2);
Object[] as = set.toArray();
//set中的两个对象是相等的,这样就出现了代码不健壮的情况
System.out.println(as[0].equals(as[1]));
总结:
ArrayList底层是数组,可以加入重复的,使用remove删除时判断的标准是equals方法。
HashSet底层是一个HashMap,不能加入重复的,重复的标准是先比较hashcode,然后比较equals,使用remove删除时同样是这样的比较原则