首页 > 代码库 > TreeSet有趣问题之add方法原理

TreeSet有趣问题之add方法原理

先看如下代码

class Worker implements Comparable<Worker> {
	private int age;
	private String name;

	public Worker(int age, String name) {
		this.setAge(age);
		this.setName(name);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.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;
		Worker other = (Worker) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public int compareTo(Worker worker) {
		return new Integer(getAge()).compareTo(new Integer(worker.getAge()));
	}

	...//setter/getter方法

}
public static void main(String[] args) {
<span style="white-space:pre">	</span>TreeSet<Worker> set = new TreeSet<Worker>();
	set.add(new Worker(21, "测试人员1"));
	set.add(new Worker(22,"测试人员2"));
	set.add(new Worker(21, "测试人员3"));
	System.out.println(set.size());
}
输出的结果是几呢?

按照写代码者的原意应该是想set里面有三个worker,按照年龄排序的.

可是执行出来的结果却是2,再细查看会发现测试人员1没有了,只有2和3.

这是为什么呢?查看源代码,发现TreeSet的add方法定义如下:

 public boolean add(E paramE)
  {
    return this.m.put(paramE, PRESENT) == null;
  }
其中this.m为TreeMap,其put方法定义如下:

public V put(K paramK, V paramV)
  {
    Entry localEntry1 = this.root;
    if (localEntry1 == null)
    {
      compare(paramK, paramK);
      this.root = new Entry(paramK, paramV, null);
      this.size = 1;
      this.modCount += 1;
      return null;
    }
    Comparator localComparator = this.comparator;
    Entry localEntry2;
    int i;
    if (localComparator != null)
    {
      do
      {
        <span style="color:#ff0000;">localEntry2 = localEntry1;
        i = localComparator.compare(paramK, localEntry1.key);
        if (i < 0) {
          localEntry1 = localEntry1.left;
        } else if (i > 0) {
          localEntry1 = localEntry1.right;
        } else {
          return localEntry1.setValue(paramV);
        }</span>
      } while (localEntry1 != null);
    }
    else
    {
      if (paramK == null) {
        throw new NullPointerException();
      }
      localObject = (Comparable)paramK;
      do
      {
        <span style="color:#ff0000;">localEntry2 = localEntry1;
        i = ((Comparable)localObject).compareTo(localEntry1.key);
        if (i < 0) {
          localEntry1 = localEntry1.left;
        } else if (i > 0) {
          localEntry1 = localEntry1.right;
        } else {
          return localEntry1.setValue(paramV);
        }</span>
      } while (localEntry1 != null);
    }
    Object localObject = new Entry(paramK, paramV, localEntry2);
    if (i < 0) {
      localEntry2.left = ((Entry)localObject);
    } else {
      localEntry2.right = ((Entry)localObject);
    }
    fixAfterInsertion((Entry)localObject);
    this.size += 1;
    this.modCount += 1;
    return null;
  }
如上红色代码,原来在TreeSet的add方法中根本就没有使用equals方法来判断两个元素是否相等,而是直接使用compareTo方法来确定添加元素在集合中的位置.

若要实现我们想要的结果,Worker中的compareTo方法应该做修改为

@Override
public int compareTo(Worker worker) {
	int index = getName().compareTo(worker.getName());
	if(index != 0){
		index = new Integer(getAge()).compareTo(new Integer(worker.getAge()));
	}
	return index;
}
如此就能得到我们想要的结果了

结论:TreeSet中确定集合中两元素相等不是使用equals方法,而是使用compareTo方法.

TreeSet有趣问题之add方法原理