Java集合框架(二)—— HashSet、LinkedHashSet、TreeSet和EnumSet
-
Set接口
前面已经简绍过Set集合,它类似于一个罐子,一旦把对象'丢进'Set集合,集合里多个对象之间没有明显的顺序。Set集合与Collection基本上完全一样,它没有提供任何额外的方法。
Set集合不容许包含相同的元素,如果试图把两个相同元素加入到同一个Set集合中,则添加操作失败,add方法返回false,且新元素不会被加入。
Set判断两个对象是否相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不会接受这两个对象,反之,只要两个对象用equals方法比较返回false,Set就会接受这两个对象(甚至这两个对象是同一个对象,Set也可把他们当成俩个对象处理),下面是Set的使用案例。
public class Test {public static void main(String[] args){Set set = new HashSet();boolean a = set.add(new String("语文"));boolean b = set.add(new String("语文"));//打印结果为true System.out.println(a);//打印结果为false System.out.println(b);/** 打印结果为[语文];* 因为两个字符串通过equals方法比较返回为true(String类默认重写了Object中equals方法),所以第二次添加失败 */System.out.println(set);} }从上面程序中可以看出,books集合两次添加的字符串对象明显不是同一个对象(因为两次都调用了new关键字来创造字符串对象),这两个字符串对象使用==运算符判断肯定返回false,但它们通过equals方法比较将返回true,所以添加失败。最后输出set集合时,将看到输出结果只有一个元素。
上面介绍的是Set集合的通用知识,完全适合HashSet、TreeSet和EnumSet三个实现类。
-
HashSet类
HashSet具有以下特点:
HashSet还有一个子类LinkedHashSet,LinkedHashSet集合也是根据元素hashCode值来决定元素存储位置,但它同时使用链表维护元素的次序,这样使的元素看起来是以插入的顺序保存的。也就是说当遍历LinkedHashSet集合里的元素时,HashSet将会按元素的添加顺序来访问集合里的元素。
LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但是在迭代访问Set里的全部元素时,将有很好的性能,因为它以列表来维护内部顺序。
public class Test {public static void main(String[] args){LinkedHashSet books = new LinkedHashSet();books.add("语文");books.add("数学");books.add("英语");//删除语文books.remove("语文");//重新添加books.add("语文");//打印结果为[数学, 英语, 语文] System.out.println(books);} }上面的集合里,元素的顺序正好与添加顺序一致。
-
TreeSet类
TreeSet是SortedSet接口的唯一实现(SortedSet接口继承Set接口),正如SortedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态。与前面的HashSet集合相比,TreeSet还提供了如下几个额外方法:
根据上面程序的运行结果可看出,TreeSet并不是根据元素的插入顺序进行排序,而是根据元素实际值来进行排序的。
与HashSet集合采用的hash算法来决定元素的存储位置不同,TreeSet采用红黑树的数据结构对元素进行排序。那么TreeSet进行排序是怎么样的呢?TreeSet支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。
-
自然排序
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小了。当一个对象调用该方法与另一个对象进行比较,例如obj1.compareTo(obj2); 如果该方法返回0,则表明这两个对象相等;如果该方法返回一个正整数,则表明obj1大于obj2;如果该方法返回一个负整数,则表明obj1小于obj2。
Java的一些常用类已经实现了Comparable接口,并提供了比较大小的标准, 下面是实现了Comparable接口的常用类:
如图所示:Integer类实现了Comparable接口:
由于上边的Integer类实现了Comparable接口,故TreeSet会调用集合元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合元素按升序排列(数据从低到高排列),这种方式就是自然排序。如果试图把一个对象添加进TreeSet时,则该对象的类必须实现Comparable接口,否则程序将会抛出ClassCastException异常。代码如下:
class Person{} public class Test {public static void main(String[] args){TreeSet<Person> persons = new TreeSet<Person>();persons.add(new Person()); System.out.println(persons); } }以上代码将会抛出:
-
定制排序
TreeSet的自然排序是根据集合元素的大小,TreeSet将它们以升序排列。如果需要完成定制排序,例如以降序排列,则可以使用Comparator接口的帮助。该接口里包含了一个int compare(T o1, T o2)方法,该方法用于比较o1、o2的大小:如果该方法返回正整数,则表明o1大于o2;如果该方法返回0,则表明o1等于o2;如果该方法返回负整数,则表明o1小于o2。
如下所示:如果需要实现定制排序(我们这实现倒序),则需要在创建TreeSet集合对象时,并提供一个Comparator对象与该TreeSet集合关联,由该Comparator对象负责集合元素的排序逻辑。
class Person{Integer age;public Person(int age){this.age = age;}@Overridepublic String toString() {return "Person [age=" + age + "]";} } public class Test {public static void main(String[] args){TreeSet<Person> persons = new TreeSet<Person>(new Comparator<Person>(){@Overridepublic int compare(Person o1, Person o2) {if(o1.age > o2.age){return -1;}else if(o1.age == o2.age){return 0;}else{return 1;}}});persons.add(new Person(2));persons.add(new Person(5));persons.add(new Person(6));//打印结果为[Person [age=6], Person [age=5], Person [age=2]]倒序 System.out.println(persons);} }上面程序创建了一个Compartor接口的匿名内部类对象,该对象负责persons集合的排序。所以当我们把Person对象添加到persons集合中时,无须Person类实现Comparable接口,因为此时TreeSet无须通过Person对象来比较大小,而是由与TreeSet关联的Compartor对象来负责集合元素的排序。
-
EnumSet类
EnumSet是一个专为枚举设计的集合类,EnumSet中所有值都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐性的指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的排序。
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。尤其是当进行批量操作(如调用containsAll和retainAll方法)时,如其参数也是EnumSet集合,则该批量操作的执行速度也非常快。
EnumSet集合不容许加入null元素。如果试图插入null元素,EnumSet将会抛出NullPointerException异常。
EnumSet类没有暴露任何构造器来创建该类的实例,程序应该通过它提供的static方法来创建EnumSet对象。它提供了如下常用static方法来创建EnumSet对象:
-
总结
转载于:https://www.cnblogs.com/guoyaohua/p/8437098.html
总结
以上是生活随笔为你收集整理的Java集合框架(二)—— HashSet、LinkedHashSet、TreeSet和EnumSet的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: RIP应用实验:
- 下一篇: 树莓派 更新 时间 时区