Java——(四)Collection之Set集合TreeSet类
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
TreeSet类
TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合
元素处于排序状态。与HashSet集合相比,TreeSet还提供了如下几个额外的方法。
1)Comparator comparator():
2)Object first():
3)Object last():
4)Object lower(Object o):
5)Object higher(Object 0):
6)SortedSet subSet(fromElemnet, toElement):
7)SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成。
8)SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。
下面出现测试了TreeSet的通用用法:
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet numsSet = new TreeSet<>();
//向TreeSet中添加四个Integer对象
numsSet.add(5);
numsSet.add(2);
numsSet.add(10);
numsSet.add(-2);
//输出集合元素,看到集合元素已经处于排序状态
System.out.println(numsSet);
//输出集合里的第一个元素
System.out.println(numsSet.first());
//输出集合里的最后一个元素
System.out.println(numsSet.last());
//返回小于4的子集,不包含4
System.out.println(numsSet.headSet(4));
//返回大于5的子集,如果、set中包含5,子集中也包含5
System.out.println(numsSet.tailSet(5));
//返回大于等于-3、小于4的子集
System.out.println(numsSet.subSet(-3, 4));
}
}
运行结果:
[-2, 2, 5, 10]
-2
10
[-2, 2]
[5, 10]
[-2, 2]
与HashSet集合采用hash算法来决定因素的存储位置不同,TreeSet采用红黑树的数据结构
来存储集合元素。TreeSet支持两种排序方法:自然排序和定制排序。默认情况下采用自然排序。
1.自然排序
TreeSet会调用集合元素的Comparable接口中的compareTo(Object obj)方法来比较元素
之间的大小关系,然后将集合元素按升序排列。当一个对象调用该方法与另一个对象进行比较时,
例如obj1.compareTo(obj2),如果该方法返回0,则表明这两个对象相等;如果该方法返回一个
正数,则表明obj1大于obj2;如果该方法返回一个负数,则表明obj1小于obj2.
下面是实现了Comparable接口的常用类:
BigDecimal、BigInteger以及所有的数值型对应的包装类:按它们对应的数值大小进行比较。
- Character:按字符的UNICODE值进行比较。
- Boolean:true对应的包装类实例大于false对应的包装类实例。
- String:按字符串中的字符UNICODE值进行比较。
- Date、Time:后面的时间、日期比前面的时间、日期大。
如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口,否则则程
序将会抛出异常。下面程序师范了这个错误。
import java.util.TreeSet;
class Err{
}
public class TreeSetErrorTest {
public static void main(String[] args) {
TreeSet tSet =new TreeSet<>();
//向TreeSet集合中添加两个Err对象
tSet.add(new Err());
tSet.add(new Err());
}
}
运行结果:
Exception in thread "main" java.lang.ClassCastException: Err cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at TreeSetErrorTest.main(TreeSetErrorTest.java:13)
上面程序试图向TreeSet集合中添加两个Err对象,添加第一个对象时,TreeSet里没有任何
因素,所以不会出现任何问题;当添加第二个Err对象时,TreeSet就会调用该对象的
ComparaTo(Object obj)方法与集合中的其他因素进行比较——如果其对应的类没有实现
Comparable接口则会引发ClassCastException异常。因此。上面程序将会在添加第二个对象的
时候引发该异常。当试图从TreeSet中取出因素时,由于第一个元素没有实现Comparable接口,
因此也会引发ClassCastException异常。
大部分类在实现compareTo(Object obj)方法时,都需要将比较对象obj强制转换成相同类型
,因为只有相同类型的两个实例次啊会比较大小。当试图把一个对象添加到TreeSet集合时,
TreeSet会调用该对象的compareTo(Object obj)方法与集合中的其他因素进行比较——这就是要
求集合中的其他因素与该因素时同一个类的实例。也就是说,向TreeSet中添加的应该是同一个类
的对象,否则也会引发ClassCastException异常。
下面程序示范了这个错误。
import java.util.Date;
import java.util.TreeSet; public class TreeSetErrorTest2 { public static void main(String[] args) { TreeSet tSet = new TreeSet<>();
tSet.add(new String("黑马程序员"));
tSet.add(new Date());
} }
运行结果:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
at java.util.Date.compareTo(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at TreeSetErrorTest2.main(TreeSetErrorTest2.java:11)
上面程序先向TreeSet集合中添加了一个字符串对象,这个操作完全正确。当添加第二个Date对
象时,TreeSet就会调用该对象的compareTo(Object obj)方法与集合中的其他因素进行比较
——Date对象的compareTo(Object obj)方法无法与字符串对象比较大小,所以上面程序将在
添加Date对象时引发异常。
如果是向TreeSet中添加的对象是程序员自定义类的对象,则可以向TreeSet中添加多种类型
的对象,前提是用户自定义类实现了Comparable接口,实现该接口实现的compareTo(Object obj)
方法没有进行强制类型转换。但当试图取出TreeSet里的集合数据时,不同类型的元素依然会发生
ClassCastException异常。
当把一个对象加入TreeSet集合中时,TreeSet调用该对象的compareTo(Object obj)方法与
容器中的其他对象比较大小,然后根据红黑树结构找到它的存储位置。如果两个对象通过
compareTo(Object obj)方法比较相等,新对象将无法添加到TreeSet集合中。他判断两个对象是否
相等的唯一标准是:两个对象通过compareTo(Object obj)方法比较是否返回0——如果通过
compareTo(Object obj)方法比较返回0,TreeSet则会认为它们相等;否则就认为它们不相等。
示例:
import java.util.TreeSet;
class Z implements Comparable{
int age;
public Z(int age){
this.age = age;
}
//重写equals()方法
@Override
public boolean equals(Object obj) {
return true;
}
@Override
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);
//输出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.first())).age);
}
}
运行结果:
true
[Z@717e5fde, Z@717e5fde]
9
程序中把同一对象再次添加到TreeSet集合中,因为z1对象的compareTo(Object obj)方法
总是返回1,虽然它的equals()方法总是返回true,但TreeSet会认为z1对象和它自己也不相等,
因此TreeSet可以添加两个z1对象。下图显示了TreeSet及Z对象在内存中的存储示意图。

从图中可以看到TreeSet对象保存的两个对象,实际上是同一元素。
如果把重写的compareTo(Object obj)方法中的返回值改为1,则运行结果如下:
false
[Z@39fc0f04]
9
如果向TreeSet中添加一个可变对象后,并且后面程序修改了该可变对象的Field,这将导致它与
其他对象的大小顺序发生了改变,但TreeSet不会再次调整它们的顺序,甚至可能导致TreeSet
中保存的这两个对象通过compareTo(Object obj)方法比较返回0.下面程序演示了这种情况。
import java.util.TreeSet;
class M implements Comparable {
int count;
public M(int count) {
this.count = count;
}
@Override
public String toString() {
return "M[count:" + count + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == M.class) {
M m = (M)obj;
if (m.count == this.count) {
return true;
}
}
return false;
}
//重写compareTo()方法,根据count来比较大小
@Override
public int compareTo(Object obj) {
M m = (M) obj;
return count > m.count ? 1 : count < m.count ? -1 : 0;
}
}
public class TreeSetTest3 {
public static void main(String[] args) {
TreeSet tsSet = new TreeSet<>();
tsSet.add(new M(5));
tsSet.add(new M(-3));
tsSet.add(new M(9));
tsSet.add(new M(-2));
//打印TreeSet集合,集合元素是有序排列的
System.out.println(tsSet);
//取出第一个元素的count值
M firstM = (M)tsSet.first();
//对第一个元素赋值
firstM.count = 20;
//取出最后一个元素
M lastM = (M)tsSet.last();
//对最后一个元素的count值赋值,与第二个元素的count值相同
lastM.count = -2;
//输出可以看到TreeSet集合里的元素处于无序状态,且有重复元素
System.out.println(tsSet);
//删除Field被改变的元素,删除失败
System.out.println(tsSet.remove(new M(-2)));
System.out.println(tsSet);
//删除field没有改变的元素,删除成功
System.out.println(tsSet.remove(new M(5)));
System.out.println(tsSet);
}
}
运行结果:
[M[count:-3], M[count:-2], M[count:5], M[count:9]]
[M[count:20], M[count:-2], M[count:5], M[count:-2]]
false
[M[count:20], M[count:-2], M[count:5], M[count:-2]]
true
[M[count:20], M[count:-2], M[count:-2]]
上面程序中的M对象对应的类正常重写了equals()方法和compareTo()方法,这两个方法都以M
对象的count实例变量作为判断的依据。当改变TreeSet集合了可变元素的Field,再试图删除该对
象时,TreeSet会删除失败,所以删除count为-2的M对象时,没有元素被删除;当删除count为5
的M对象时,可以看到元素被删除,这表明TreeSet可以删除没有被修改的Field,且不与其他被修
改Field的对象重复的对象。
2.定制排序
TreeSet的自然排序是根据集合元素的大小,TreeSet将它们一升序排序。如果需要实现定制
排序,例如以降序排列,则可以通过Comparator接口的帮助。该接口里包含了一个int compare
(T o1, T o2)方法,该方法用于比较o1和o2的大小:如果该方法返回正整数,则表明o1大于o2;
如果该方法返回0,则表明o1等于o2;如果该方法返回负整数,则表明o1小于o2。
实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator对象与该TreeSet
集合关联,由该Comparator对象负责集合元素的排序。
import java.util.Comparator;
import java.util.TreeSet; class C {
int age; public C(int age) {
this.age = age;
} @Override
public String toString() { return "C[age:" + age + "]";
}
} public class TreeSetTest4 { public static void main(String[] args) { TreeSet tSet = new TreeSet<>(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
C c1 = (C) o1;
C c2 = (C) o2;
return c1.age > c2.age ? -1 : c1.age < c2.age ? 1 : 0;
}
});
tSet.add(new C(5));
tSet.add(new C(-3));
tSet.add(new C(9));
System.out.println(tSet);
} }
运行结果:
[C[age:9], C[age:5], C[age:-3]]
Java——(四)Collection之Set集合TreeSet类的更多相关文章
- Java中Collection、Map常用实现类研究分析
接口/实现类 描述 key是否可为null 为null是否报错 key是否重复 key重复是否报错 key是否和添加一致 是否线程安全 List 一组元素的集合 ArrayList 基于数组存储,读取 ...
- Java中Collection和Collections的区别(引用自:http://www.cnblogs.com/dashi/p/3597937.html)
1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对象进行基本操作的通用接口方法.Collection接口在Java 类库中有很多具体的实现.Co ...
- java类库 collection与collections (转)
http://www.cnblogs.com/dashi/p/3597937.html Java中Collection和Collections的区别 1.java.util.Collection 是一 ...
- Java中Collection和Collections的区别(转载)
转载来源:http://www.cnblogs.com/dashi/p/3597937.html 1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对 ...
- Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类
Collection 之 Set 实现类: HashSet TreeSet 特点: 无序. 元素不可重复. (如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false ...
- Java基础学习(四)-- 接口、集合框架、Collection、泛型详解
接口 一.接口的基本概念 关键字为:Interface,在JAVA编程语言中是一个抽象类型,是抽象方法的集合.也是使用.java文件编写. 二.接口声明 命名规范:与类名的命名规范相同,通常情况下 ...
- Java自学第6期——Collection、Map、迭代器、泛型、可变参数、集合工具类、集合数据结构、Debug
集合:集合是java中提供的一种容器,可以用来存储多个数据. 集合和数组既然都是容器,它们有啥区别呢? 数组的长度是固定的.集合的长度是可变的. 数组中存储的是同一类型的元素,可以存储基本数据类型值. ...
- Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)
Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...
- 复习java基础第三天(集合:Collection、Set、HashSet、LinkedHashSet、TreeSet)
一.Collection常用的方法: Java 集合可分为 Set.List 和 Map 三种体系: Set:无序.不可重复的集合. List:有序,可重复的集合. Map:具有映射关系的集合. Co ...
随机推荐
- 初识Vim
在Windows系统安装Vim后桌面上会添加gVim.gVim Easy.gVim Read-only 三个快捷方式. gVim 指向主程序,gVim Easy.gVim Read-only 也是,但 ...
- nutch 二次开发
/*深度控制*/ 深度控制:nutch是广域网的深度遍历,我们需要的是垂直采集(即只采集某一个栏目),举例,索引页总计20页,如果只有下一页,则深度为20,如果是1 2 3 4 5……20则深度为2即 ...
- seajs 和spm的使用简介
说实话, 前端开发是一个令人头痛的事情. nodejs出现了很久了, 一直不是很习惯用nodejs, 当初刚出来的时候, 就下载了express, 想搭建个网站, 结果不是我的菜, 愣是用的不习惯,也 ...
- 转载:用Dreamweave cs 5.5+PhoneGap+Jquery Mobile搭建移动开发
转载地址:http://blog.csdn.net/haha_mingg/article/details/7900221 移动设备应用开发有多难,只要学会HTML5+Javascript就可以.用Dr ...
- Spring MVC 解读——@RequestMapping (2)(转)
转自:http://my.oschina.net/HeliosFly/blog/214438 Spring MVC 解读——@RequestMapping 上一篇文章中我们了解了Spring如何处理@ ...
- 【PPC】Qemu怎么玩儿
1. 编译Qemu这里不建议使用自动安装,手工编译下.Qemu源代码的质量很高,什么环境都能编译过.tar -xzvf qemu.tar.gzmkdir build-qemucd build-qemu ...
- 【HDOJ】1930 And Now, a Remainder from Our Sponsor
简单字符串. #include <stdio.h> #define MAXLEN 160 char buf[MAXLEN]; ], parts[]; void getpart(int x) ...
- bzoj2734
非常巧妙地题目对于一个数x列出这样的矩阵x 2x 4x 8x ……3x 6x 12x 24x ………………………………不难方案数就是求取数不相邻的方案数考虑矩阵宽不超过logn,所以可以用状压dp解决 ...
- 查看Mysql执行计划
使用navicat查看mysql执行计划: 打开profile分析工具: 查看是否生效:show variable like ‘%profil%’; 查看进程:show processlist; 选择 ...
- Defining as a "long" or "int" type throws an error on startup
solr启动时候,报如下异常: [java] view plaincopy SEVERE: org.apache.solr.common.SolrException at org.a ...