Java   集合11TreeSet  存储自定义类

基于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() ,当返回值为零时。视为同一个对象

猜你喜欢

转载自blog.csdn.net/Stitch__/article/details/82431268