基于TreeMap 。使用元素的自然排序对元素进行排序,或由Comparator集合创建时提供,是有特有方法的
使用代码:
package Collection;
import java.util.*;
//使用 TreeSet
public class TreeSetDemo_Set {
public static void main(String[] args){
Set set = new TreeSet();
//添加元素
set.add("bde");
set.add("aaa");
set.add("bac");
//获取元素
for(Iterator it = set.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果:
aaa
bac
bde//是按照从小到大排序的
存储自定义对象:
package Collection;
import java.util.*;
//使用 TreeSet
class Beauty{
private String name;
private int age;
public Beauty(String name,int age) {
this.name = name;
this.age= age;
}
}
public class TreeSetDemo_Set {
public static void main(String[] args){
Set set = new TreeSet();
//添加元素
set.add(new Beauty("chenyu",18));
set.add(new Beauty("Luoyan",16));
set.add(new Beauty("Xiuhua",19));
//获取元素
for(Iterator it = set.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
出现异常;ClassCastException: Collection.Beauty cannot be cast to java.base/java.lang.Comparable 类型转换异常(Beauty 无法转化为 Comparable 类型)
原因分析:
查看TreeSet 的源码,发现,TreeSet 的add 方法的内部实现为: 将传入的对象强转为Comparable 类型,再调用comparaTo 这个方法进行比较,从而实现自然排序。
在学习string 这个类的时候讲过 Comparable 这个接口可以实现自然排序(主要是里面有一个comparaTo 的方法实现对象的比较,比较的规则自己写)。
但是这里有一个问题:
类型简要能进行转化那必须是对象间存在某种联系。在输入字符串的时候,能够正确地输出自然排序大的结果是因为,String 类实现了 Comparable 这个接口,并且它定义了自己进行对象比较的规则。
因此解决问题的方法:
Beauty 类 实现Comparable 这个接口,并且写自己的comparaTo 方法。
代码:
package Collection;
import java.util.*;
//使用 TreeSet
class Beauty implements Comparable{
private String name;
private int age;
public Beauty(String name,int age) {
this.name = name;
this.age= age;
}
@Override
public String toString() {
return this.name+" "+this.age;
}
@Override
//重写比较函数//建立自己的比较规则
public int compareTo(Object o) {
if(!(o instanceof Beauty)){
throw new ClassCastException("类型转化错误");
}
Beauty b = (Beauty)o;
return this.age-b.age;
}
}
public class TreeSetDemo_Set {
public static void main(String[] args){
Set set = new TreeSet();
//添加元素,存储自定义 元素
set.add(new Beauty("chenyu",18));
set.add(new Beauty("Luoyan",16));
set.add(new Beauty("Xiuhua",19));
//获取元素
for(Iterator it = set.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果:
Luoyan 16
chenyu 18
Xiuhua 19
注意在这里发现了一个问题: 当我没有重写toString 方法时,打印的结果是 对象的 类名+哈希值(这和直接打印对象的结果是一样的),因此可知:迭代器的 next 方法在底层是调用了对象的 toString 方法的。
同时如果我们修改数据,创建两个年龄一样名字不一样的的对象:
set.add(new Beauty("chenyu",18));
set.add(new Beauty("Luoyan",16));
set.add(new Beauty("Xiuhua",18));
运行结果:
Luoyan 16
chenyu 18//会被当作重复数据
重点分析:HashSet 对的对数据的惟一性操作,是因为HashSet 的 add 方法内调用了 hashCode 和equals 两个方法 ; 而TreeSet 的 add 方法中 数据的的自然顺序输出是因为 强转为 Comparable 并且调用了 comparaTo 方法,同时保证数据的惟一性没有调用equals 方法,而是都通过 comparaTo 方法 ,当返回值为0,则视为元素相等。因此之前写的比较函数是有问题的
解决办法:
在写比较函数comparaTo 函数时,要分清楚主次。主要条件相同时,再比较次要条件。如果两个条件都相同,那么就返回0(两个对象相等)
//重写比较函数//要分清楚主次
public int compareTo(Object o) {
if(!(o instanceof Beauty)){
throw new ClassCastException("类型转化错误");
}
Beauty b = (Beauty)o;
int temp = this.age-b.age;
return temp==0?this.name.compareTo(b.name):temp;
//解释:年龄不一样时,按照年龄排序;年龄一样时,按照名字排序。都一样返回0.就是一样的元素
}
运行结果:
Luoyan 16
Xiuhua 18
chenyu 18
**TreeSet 存储的内部结构:**
在内部存储的时候是按照二叉树排序的,左大右小。同时查找的方法用到折半查找,来提高效率(不然每一个存入的数据都要从根开始比较,效率就有一点低)
总结:TreeSet 可以对元素进行自然排序(在存入的时候排序),底层使用的存储结构是:二叉树。排序和保证唯一性都是依赖的对象比较方法/compareTo() ,当返回值为零时。视为同一个对象