TreeSet集合解析
TreeSet是实现Set接口的实现类。所以它存储的值是唯一的,同时也可以对存储的值进行排序,排序用的是二叉树原理。所以要理解这个类,必须先简单理解一下什么是二叉树。
二叉树原理简析
假如有这么一个集合TreeSet<Integer>是[5,11,6,5,23,14]
用二叉树是怎么排序的呢?

二叉树遍历方法比较多,有兴趣自己百度看下吧。这里只需要知道元素是怎么插入到二叉树即可。小的存储在左边(负数),大的存储在右边(正数),相等不存储。
TreeSet的基本使用
@Test
public void test() {
Set<Integer> set = new TreeSet<Integer>();
set.add(2);
set.add(22);
set.add(24);
set.add(2);
for (int i : set) {
System.out.println(i);
}
}
输出结果
2
22
24
可以知道,TreeSet集合不仅可以保证集合元素的唯一性,还可以排序。
如果TreeSet里面存储的是对象呢?会出现什么情况呢?
public static void main(String[] args) {
        User u1 = new User("Kevin", 72);
        User u2 = new User("Jack", 22);
        User u3 = new User("Erik", 32);
        User u4 = new User("Blank", 72);
        Set<User> set = new TreeSet<User>();
        set.add(u1);
        set.add(u2);
        set.add(u3);
        set.add(u4);
        for (User u :
                set) {
            System.out.println(u);
        }
    }
输出结果
Exception in thread "main" java.lang.ClassCastException: com.kevin.exercise10.User cannot be cast to java.lang.Comparable
at java.util.TreeMap.put(TreeMap.java:542)
at java.util.TreeSet.add(TreeSet.java:238)
at com.kevin.exercise10.TreeSetTest.main(TreeSetTest.java:23)
报错了,因为集合里面的是对象,对象不能转换为比较可比较对象。
如果想根据年龄排序,打印出各个对象(toString方法),应该怎么做呢?在API里面搜索一下Comparable,发现是个接口,那么我们就可以让Students类实现Comparable接口方法,这样Students对象就成为了可比较对象了。
User类实现Comparable接口方法:
public class User implements Comparable<User> {
    private String name;
    private int age;
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public int compareTo(User u) {
        int num = this.age - u.age;
        return this.age - u.age;
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public User() {
    }
}
为什么是this.age-u.age?this.age代表调用时的对象的age,返回的如果是正数(比u.age大),就存储在右边。返回的是如果是负数(比u.age小),就存储在左边。如果等于0,就不存储。
这就出问题了,如果两个人不同名字,同样年龄,this.age - o.age = 0,不就存不进二叉树了吗?
验证一下:
public static void main(String[] args) {
        User u1 = new User("Kevin", 72);
        User u2 = new User("Jack", 22);
        User u3 = new User("Erik", 32);
        User u4 = new User("Blank", 72);
        Set<User> set = new TreeSet<User>();
        set.add(u1);
        set.add(u2);
        set.add(u3);
        set.add(u4);
        for (User u :
                set) {
            System.out.println(u);
        }
    }
输出结果:
User{name='Jack', age=22}
User{name='Erik', age=32}
User{name='Kevin', age=72}
所以需要改进一下User类的compareTo方法,保证同年龄,但是不同名字的学生也能存进二叉树。
@Override
public int compareTo(User u) {
int num = this.age - u.age;
return num == 0 ? this.name.compareTo(u.name) : num;
}
这样就可以把四个不同的对象存储进来,并且先按照年龄排序,年龄相同的再按照字符串排序。
输出结果:
User{name='Jack', age=22}
User{name='Erik', age=32}
User{name='Blank', age=72}
User{name='Kevin', age=72}
---------------------------------------------------------------------------------------
除了这种方式可以实现排序以外,还有一种方式可以实现排序。
TreeSet有这么一个构造方法:
TreeSet(Comparator<? super E> comparator) 构造一个新的,空的树集,根据指定的比较器进行排序。
Comparator是什么呢?API文档看一下:Interface Comparator<T>,是一个接口,里面有一个要实现的接口方法:int compare(T o1, T o2) 比较其两个参数的顺序。
例如,我们要对字符串的长度进行排序,长度相同的安装字符串排序:
public class TreeSetTest2 {
    public static void main(String[] args) {
        TreeSet<String> set = new TreeSet<String>(new SortedByLen());
        set.add("abc");
        set.add("abcd");
        set.add("b");
        set.add("a");
        set.add("abab");
        System.out.println(set);
    }
}
class SortedByLen implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        int num = s1.length() - s2.length();
        return num == 0 ? s1.compareTo(s2) : num;
    }
}
需要注意的是重写compare方法的o1,o2。o1代表调用的对象,o2代表集合中的对象。两种实现排序方式视情况而用。
(1)自然顺序(Comparable)
- TreeSet类的add()方法中会把存入的对象提升为Comparable类型
 - 调用对象的compareTo()方法和集合中的对象比较
 - 根据compareTo()方法返回的结果进行存储
 (2)比较器顺序(Comparator)
- 创建TreeSet的时候可以指定一个Comparator
 - 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
 - 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
 (3)两种方式的区别
- TreeSet构造函数什么都不传,默认按照类中Comparable的顺序(没有就报错ClassCastException)
 - TreeSet如果传入Comparator,就优先按照Comparator
 
如果不想保证元素的唯一性,改一下compare方法就可以了,永远不要让它返回0。
原文参考【https://www.javazhiyin.com/】
TreeSet集合解析的更多相关文章
- TreeSet集合的add()方法源码解析(01.Integer自然排序)
		
>TreeSet集合使用实例 >TreeSet集合的红黑树 存储与取出(图) >TreeSet的add()方法源码 TreeSet集合使用实例 package cn.itca ...
 - map,set,list等集合解析以及HashMap,LinkedHashMap,TreeMap等该选谁的的区别
		
前言: 今天在整理一些资料时,想起了map,set,list等集合,于是就做些笔记,提供给大家学习参考以及自己日后回顾. Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允 ...
 - TreeSet集合深入了解--------攻击原理
		
Set接口Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false.(无序,不可重复 )Set判断两个对象相同不是使用==运算符,而是根据equals方法.也就是说 ...
 - TreeSet集合
		
TreeSet集合 TreeSet集合是一个依靠TreeMap实现的有序集合,内部存储元素是自动按照自然排序进行排列,所以如果想要保留存储时的顺序,那么就不建议使用TreeSet. TreeSet继承 ...
 - Java TreeSet集合排序  &&  定义一个类实现Comparator接口,覆盖compare方法 && 按照字符串长度排序
		
package TreeSetTest; import java.util.Iterator; import java.util.TreeSet; import javax.management.Ru ...
 - TreeSet集合如何保证元素唯一
		
TreeSet: 1.特点 TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列 2.使用方式 a.自然顺序(Comparable) TreeSet类的add()方法中会 ...
 - TreeSet集合排序方式一:自然排序Comparable
		
TreeSet集合默认会进行排序.因此必须有排序,如果没有就会报类型转换异常. 自然排序 Person class->实现Comparable,实现compareTo()方法 package H ...
 - TreeSet集合的自然排序与比较器排序、Comparable接口的compareTo()方法
		
[自然排序] package com.hxl; public class Student implements Comparable<Student> { private String n ...
 - java-Set集合、HashSet集合、LinkedHashSet集合和TreeSet集合
		
1.Set集合,无索引,不可以重复,无序(存取不一致) public class Demo { public static void main(String[] args) { //demo1(); ...
 
随机推荐
- MySQL下载安装配置和Navicat for MySQL的安装配置
			
MySQL 一.下载 地址:MySQL :: Download MySQL Installer 选择那个几百M的msi文件下载 二.安装 第一步: 安装许可 双击安装文件,在如下图所示界面中勾选&qu ...
 - 网络-udp
			
1. 网络:把双方或者多方的设备(电脑,智能手机,ipad等)连接起来的一个工具 1.1 学习网络的目的: 通过网络把数据从一方传递到另外一方,完成数据的共享 2. ip地址 2.1: ...
 - Python_CRC32
			
#计算文件的CRC32值 import sys import zlib import os.path filename=sys.argv[1] print(filename) if os.path.i ...
 - 利用box-shadow属性实现页面层叠效果
			
效果图如下 box-shadow的语法 代码展示 .footer { color: #777; padding: 10px 15px; height: 20px; text-align: center ...
 - Tomcat配置与优化(内存、并发、管理)与性能监控
			
原文链接:http://blog.csdn.net/xyang81/article/details/51530979 一.JVM内存配置优化 在开发当中,当一个项目比较大时,依赖的jar包通常比较多, ...
 - springboot项目利用devtools实现热部署,改动代码自动生效
			
一.前言 spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去.原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后 ...
 - Spring Cloud Eureka Server高可用注册服务中心的配置
			
前言 Eureka 作为一个云端负载均衡,本身是一个基于REST的服务,在 Spring Cloud 中用于发现和注册服务. 那么当成千上万个微服务注册到Eureka Server中的时候,Eurek ...
 - linux内核裁剪及编译可加载模块
			
一:linux内核裁剪: 1:编译内核源码: 今天的重点内容是内核驱动的编写,在编写驱动之前首先的了解linux内核源码,linux主要是由五个子系统组成:进程调度,内存管理,文件系统,网络接口以及进 ...
 - VirtualBox报错:不能为虚拟电脑XXX打开一个新任务
			
报错产生的背景 今天在这里下载了一个用于VirtualBox的Kali Linux虚拟机文件(使用VirtualBox可以直接打开使用,不用执行安装过程).但是将该文件导入到VirtualBox中之后 ...
 - YII框架视图模块化
			
在实际项目开发中,有很多地方我们在不同页面我们会重复利用它,如菜单栏... 下面是将这类型进行模块化处理,使其能在不同页面中重复利用... 案例: 效果图如下: 1.在YII中的路径如下: 2.在le ...