向TreeSet中add的对象必须实现Comparable接口,并且是同一类型。否则会引起java.lang.ClassCastException异常。
class Err{}
public class TreeSetErrorTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
// 向TreeSet集合中添加两个Err对象
ts.add(new Err());
ts.add(new Err()); //①
}
}
public class TreeSetErrorTest2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
//HashSet ts = new HashSet();
// 向TreeSet集合中添加两个对象
ts.add(new String("疯狂Java讲义"));
ts.add(new Date()); // ①
}
}
对于TreeSet集合而言,它判断两个对象是否相等的唯一标准是:两个对象通compareTo(Object obj)方法比较是否返回0,如果 为0,TreeSet则会认为它们相等;否则就认为它们不相等。
当需要把一个对象放入TreeSet中,重写该对象对应类的equals()方法时,应该保证该方法与compareTo(Object obj)方法有一致的结果,其规则是:如果两个对象通过equals()方法比较返回true时,这两个对象通过compareTo(Object obj)方法比较应该返回0.
class Z implements Comparable
{
int age;
public Z(int age)
{
this.age = age;
}
// 重写equals()方法,总是返回true
public boolean equals(Object obj)
{
return true;
}
// 重写了compareTo(Object obj)方法,总是返回1
public int compareTo(Object obj)
{
return 1;
}
}
public class TreeSetTest2
{
public static void main(String[] args)
{
TreeSet set = new TreeSet();
Z z1 = new Z(6);
set.add(z1);
set.add(z1);
// 第二次添加同一个对象,输出true,表明添加成功
System.out.println(set.add(z1)); //①
// 下面输出set集合,将看到有两个元素
System.out.println(set);
// 修改set集合的第一个元素的age变量
((Z)(set.first())).age = 9;
// 输出set集合的最后一个元素的age变量,将看到也变成了9
System.out.println(((Z)(set.last())).age);
System.out.println(set.add(z1));
System.out.println(set);
Iterator it = set.iterator();
while(it.hasNext()){
Z z = (Z)it.next();
System.out.println("age = "+z.age);
}
}
}
true
[c83.Z@15db9742, c83.Z@15db9742, c83.Z@15db9742]
9
true
[c83.Z@15db9742, c83.Z@15db9742, c83.Z@15db9742, c83.Z@15db9742]
age = 9
age = 9
age = 9
age = 9
class R2 implements Comparable
{
int count;
public R2(int count)
{
this.count = count;
}
public String toString()
{
return "R[count:" + count + "]";
}
// 重写equals方法,根据count来判断是否相等
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if(obj != null && obj.getClass() == R2.class)
{
R2 r = (R2)obj;
return r.count == this.count;
}
return false;
}
// 重写compareTo方法,根据count来比较大小
public int compareTo(Object obj)
{
R2 r = (R2)obj;
return count > r.count ? 1 :
count < r.count ? -1 : 0;
}
}
public class TreeSetTest3
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new R2(5));
ts.add(new R2(-3));
ts.add(new R2(9));
ts.add(new R2(-2));
// 打印TreeSet集合,集合元素是有序排列的
System.out.println(ts); // ①
// 取出第一个元素
R2 first = (R2)ts.first();
// 对第一个元素的count赋值
first.count = 20;
// 取出最后一个元素
R2 last = (R2)ts.last();
// 对最后一个元素的count赋值,与第二个元素的count相同
last.count = -2;
// 再次输出将看到TreeSet里的元素处于无序状态,且有重复元素
System.out.println(ts); // ②
// 删除实例变量被改变的元素,删除失败
System.out.println(ts.remove(new R2(-2))); // ③
System.out.println(ts);
// 删除实例变量没有被改变的元素,删除成功
System.out.println(ts.remove(new R2(5))); // ④
System.out.println(ts);
}
}
[R[count:-3], R[count:-2], R[count:5], R[count:9]]
[R[count:20], R[count:-2], R[count:5], R[count:-2]]
false
[R[count:20], R[count:-2], R[count:5], R[count:-2]]
true
[R[count:20], R[count:-2], R[count:-2]]
当执行了代码
System.out.println(ts.remove(new R2(5))); // ④
后,TreeSet会对集合中的元素重新索引(不是重新排序),接下来就可以删除TreeSet中的元素了,包括那些被修改过实例变量的元素。与HashSet类似的是,如果TreeSet中包含了可变对象,当可变对象的实例变量被修改时,TreeSet在处理这些对象时将非常复杂,而且容易出错。为了让程序更加健壮,推荐不要修改放入HashSet和TreeSet集合中元素的关键实例变量。
TreeSet实现定制排序:
class M
{
int age;
public M(int age)
{
this.age = age;
}
public String toString()
{
return "M[age:" + age + "]";
}
}
public class TreeSetTest4
{
public static void main(String[] args)
{
// 此处Lambda表达式的目标类型是Comparator
TreeSet ts = new TreeSet((o1 , o2) ->
{
M m1 = (M)o1;
M m2 = (M)o2;
// 根据M对象的age属性来决定大小,age越大,M对象反而越小
return m1.age > m2.age ? -1
: m1.age < m2.age ? 1 : 0;
});
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(9));
System.out.println(ts);
}
}
[M[age:9], M[age:5], M[age:-3]]