• Set 集合

Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。

Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法。也就是说两个对象equals比较返回true,Set集合是不会接受这个两个对象的。

Set是Collection子接口;Set和Collection基本上一样,一点除外:Set无法记住添加的顺序,不允许包含重复的元素。

当试图添加两个相同元素进Set集合,添加操作失败,add()方法返回false。



  • 常用子类:

HashSet:散列存放

TreeSet:有序存放

LinkedHashSet:使用链表



  • HashSet

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet 具有以下特点:

1,不能保证元素的排列顺序,散列存储:不记录添加顺序,排列顺序时,顺序有可能发生变化

2,HashSet 不是线程安全的,多个线程访问一个HashSet要使用同步代码

3,集合元素可以使 null,但是最多只能有一个

4,当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

5,Hash算法价值体现在速度,可以保证查询快速执行。当从HashSet中访问元素时,HashSet先计算该元素的hashCode(也就是该对象的hashCode方法返回值),然后直接到该HashCode对应的位置取出该元素;

在这里对象的hashCode就好比是数组里的索引,但是不是索引。

6,如果需要某个类的对象保存到HashSet集合中,覆写该类的equals()和hashCode()方法,应该尽量保证两个对象通过equals比较返回true时,他们的hashCode返回也相等。

说到这里,就不得不提object类中的hashCode() 方法:

HashSet 集合判断两个元素相等的标准:两个对象通过 equals() 方法比较相等,并且两个对象的 hashCode() 方法返回值也相等。如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。重写 hashCode() 方法的基本原则:

1:在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值

2:当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等

3:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值

关于hashset值得注意的是:

  1. package tz.web.main;
  2.  
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import com.google.common.collect.Sets;
  6.  
  7. public class Linkin
  8. {
  9.  
  10. private String name;
  11.  
  12. public Linkin(String name)
  13. {
  14. super();
  15. this.name = name;
  16. }
  17.  
  18. public String getName()
  19. {
  20. return name;
  21. }
  22.  
  23. public void setName(String name)
  24. {
  25. this.name = name;
  26. }
  27.  
  28. public static void main(String[] args)
  29. {
  30. Linkin linkin1 = new Linkin("huhu1");
  31. Linkin linkin2 = new Linkin("huhu2");
  32. Set<Linkin> set = Sets.newHashSet(linkin1,linkin2);
  33. System.out.println(set.size());//2
  34. linkin1.setName("LinkinPark");
  35. //这里的hashcode值变了,在删除的时候按照这个linkin1的hashcode值去找对象,结果就根本找不见了,所以没有删掉
  36. set.remove(linkin1);
  37. System.out.println(set.size());//2
  38. Iterator<Linkin> it = set.iterator();
  39. while(it.hasNext())
  40. {
  41. it.next();
  42. //从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
  43. it.remove();
  44. }
  45. System.out.println(set.size());//1
  46. }
  47.  
  48. @Override
  49. public int hashCode()
  50. {
  51. final int prime = 31;
  52. int result = 1;
  53. result = prime * result + ((name == null) ? 0 : name.hashCode());
  54. return result;
  55. }
  56.  
  57. @Override
  58. public boolean equals(Object obj)
  59. {
  60. if (this == obj)
  61. return true;
  62. if (obj == null)
  63. return false;
  64. if (getClass() != obj.getClass())
  65. return false;
  66. Linkin other = (Linkin) obj;
  67. if (name == null)
  68. {
  69. if (other.name != null)
  70. return false;
  71. }
  72. else if (!name.equals(other.name))
  73. return false;
  74. return true;
  75. }
  76.  
  77. }

  • LinkedHashSet

LinkedHashSet 是 HashSet 的子类

LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。LinkedHashSet 不允许集合元素重复。



  1. import java.util.LinkedHashSet;
  2. import java.util.Set;
  3.  
  4. /**
  5. *
  6. * @version 1L
  7. * @author LinkinPark
  8. * @since 2014-11-10
  9. * @motto 梦似烟花心似水,同学少年不言情
  10. * @desc ^遍历LinkedHashSet集合里面的元素时,LinkedHashSet会按元素的添加顺序来访问集合里面的元素
  11. */
  12. public class Linkin
  13. {
  14.  
  15. public static void main(String[] args)
  16. {
  17. Set<String> names = new LinkedHashSet<String>();
  18. names.add("Binger");
  19. names.add("LinkinPark");
  20. //Binger LinkinPark
  21. for (String string : names)
  22. {
  23. System.out.println(string);
  24. }
  25. }
  26.  
  27. }

  • TreeSet



如果试图把一个对象添加到TreeSet时,该对象必须实现Comparable接口,否则程序会抛出异常。

使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,参与排序的元素必须是同一类型的,不然会发生ClassCastException异常,

TreeSet是SortedSet接口唯一的实现,与HashSet相比额外的方法有:

Comparator comparator() 返回当前Set使用的Comparator 若返回null,表示以自然顺序排序。

Object first() 返回此 set 中当前第一个(最低)元素。 

Object last() 返回此 set 中当前最后一个(最高)元素。 

SortedSet subSet(Object  fromElement, E toElement) 返回此 set 的部子集,其元素从 fromElement(包括)到 toElement(不包括)。 

SortedSet headSet(Object  toElement) 返回此 set 的部分子集,其元素严格小于 toElement。 

SortedSet tailSet(Object  fromElement) 返回此 set 的部分子集,其元素大于等于 fromElement。 



TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。

  • 自然排序

TreeSet会调用元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合里的元素按升序排列.此时需要排序元素的类必须实现Comparable接口,并覆写其int compareTo(Object o)方法;

该方法用于比较对象,若:obj1,compareTo(obj2),返回0,表示两个对象相等,若返回一个正整数,表示obj1大于obj2,若返回一个负整数,表示obj1小于obj2;

对于TreeSet集合而言,判断两个对象相等的标准是:compareTo()方法比较返回 0。

  • Comparable 的典型实现:

BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较

Character:按字符的 UNICODE 值来进行比较

Boolean:true 对应的包装类实例大于 false 对应的包装类实例

String:按字符串中字符的 UNICODE 值进行比较

Date、Time:后边的时间、日期比前面的时间、日期大



因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。

  1. import java.util.Set;
  2. import java.util.TreeSet;
  3.  
  4. /**
  5. *
  6. * @version 1L
  7. * @author LinkinPark
  8. * @since 2014-11-10
  9. * @motto 梦似烟花心似水,同学少年不言情
  10. * @desc ^如果试图把一个对象添加到TreeSet时,该对象必须实现Comparable接口,否则程序会抛出异常。
  11. */
  12. public class Linkin implements Comparable
  13. {
  14. private String name;//名字
  15. private Integer age;//年龄
  16.  
  17. public Linkin(String name, Integer age)
  18. {
  19. this.name = name;
  20. this.age = age;
  21. }
  22.  
  23. public String getName()
  24. {
  25. return name;
  26. }
  27.  
  28. public void setName(String name)
  29. {
  30. this.name = name;
  31. }
  32.  
  33. public Integer getAge()
  34. {
  35. return age;
  36. }
  37.  
  38. public void setAge(Integer age)
  39. {
  40. this.age = age;
  41. }
  42.  
  43. @Override
  44. public int compareTo(Object obj)
  45. {
  46. Linkin s = (Linkin)obj;
  47. return this.age - s.age;
  48. }
  49.  
  50. public static void main(String[] args)
  51. {
  52. Linkin linkin1 = new Linkin("LinkinPark", 25);
  53. Linkin linkin2 = new Linkin("Binger", 24);
  54. Set<Linkin> linkins = new TreeSet<Linkin>();
  55. linkins.add(linkin1);
  56. linkins.add(linkin2);
  57. for (Linkin linkin : linkins) {
  58. //Binger LinkinPark
  59. System.out.println(linkin.getName());
  60. }
  61. }
  62.  
  63. }
  • 定制排序

TreeSet的自然排序是根据元素的大小进行升序排序的,若想自己定制排序,比如降序排序,就可以使用Comparator接口了。该接口包含int compare(Object o1,Object o2)方法,用于比较两个对象的大小,比较结果和compareTo方法一致。要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,该对象里负责集合元素的排序逻辑。如果需要实现定制排序,则需要在创建 TreeSet
集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑。

  1. import java.util.Comparator;
  2. import java.util.Set;
  3. import java.util.TreeSet;
  4.  
  5. /**
  6. *
  7. * @version 1L
  8. * @author LinkinPark
  9. * @since 2014-11-10
  10. * @motto 梦似烟花心似水,同学少年不言情
  11. * @desc ^
  12. */
  13. public class Linkin
  14. {
  15. private String name;//名字
  16. private Integer age;//年龄
  17.  
  18. public Linkin(String name, Integer age)
  19. {
  20. this.name = name;
  21. this.age = age;
  22. }
  23.  
  24. public String getName()
  25. {
  26. return name;
  27. }
  28.  
  29. public void setName(String name)
  30. {
  31. this.name = name;
  32. }
  33.  
  34. public Integer getAge()
  35. {
  36. return age;
  37. }
  38.  
  39. public void setAge(Integer age)
  40. {
  41. this.age = age;
  42. }
  43.  
  44. public static void main(String[] args)
  45. {
  46. Linkin linkin1 = new Linkin("LinkinPark", 25);
  47. Linkin linkin2 = new Linkin("Binger", 24);
  48. Set<Linkin> linkins = new TreeSet<Linkin>(
  49. new Comparator<Linkin>()
  50. {
  51. @Override
  52. public int compare(Linkin o1, Linkin o2)
  53. {
  54. Linkin obj1 = (Linkin) o1;
  55. Linkin obj2 = (Linkin) o2;
  56. return obj1.getAge() - obj2.getAge();
  57. }
  58. });
  59. linkins.add(linkin1);
  60. linkins.add(linkin2);
  61. for (Linkin linkin : linkins) {
  62. //Binger LinkinPark
  63. System.out.println(linkin.getName());
  64. }
  65. }
  66.  
  67. }



各Set实现类的性能分析:

HashSet和TreeSet是Set的2个典型实现,到底如何选择HashSet和TreeSet呢?HashSet的性能总是比TreeSet好,特别是在最常用的添加,查询元素等操作,因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。LinkedHashSet是HashSet的一个子类,对于普通的插入,删除操作,LinkedHashSet总是比HashS慢一点,这是由维护链表所带来的额外开销造成的。不过真是因为有了链表,遍历LinkedHashSet会更快。实际开发中HashSet使用的是比较多的,其他的基本用不到。





linkin大话数据结构--Set的更多相关文章

  1. linkin大话数据结构--Collection和Iterator

    linkin大话数据结构--Collection和Iterator Java 集合就像一种容器,可以把多个对象的引用放入容器中.Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系 ...

  2. linkin大话数据结构--泛型

    泛型(Generic) 什么是泛型? java5开始出现的一种对Java语言类型的一种拓展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数类型时指定的类型占位符,就好比方法的形式参数 ...

  3. linkin大话数据结构--字符串,数组,list之间的互转

    在实际开发中,我们经常会用到字符串,字符数组,字符list,当然也会不可避免的进行这3者之间的互相转换. 在使用到Apache和Google下的common包,可以这样子实现: package tz. ...

  4. linkin大话数据结构--Google commons工具类

    package tz.web.dao.bean; import java.util.Arrays; import java.util.Collection; import java.util.List ...

  5. linkin大话数据结构--Queue

    链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必按顺序存储,所以插入和删除速度超 ...

  6. linkin大话数据结构--List

    List:Collection子接口 List是有序的集合,集合中每个元素都有对应的顺序序列.List集合可使用重复元素,可以通过索引来访问指定位置的集合元素(顺序索引从0开始),List集合默认按元 ...

  7. linkin大话数据结构--apache commons工具类

    Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动. 一.Commons BeanUtils 说明:针对Bean的一个工具集.由于Bean往往是有一堆ge ...

  8. linkin大话数据结构--数组

    数组概述:如何正确理解数组?数组也是一种类型 数组是多个相同类型数据的组合,实现对这些数据的统一管理.数组属引用类型,数组型数据是对象(Object),数组中的每个元素相当于该对象的成员变量数组中的元 ...

  9. linkin大话数据结构--Collections类

    操作集合的工具类:Collections Collections 是一个操作 Set.List 和 Map 等集合的工具类.Collections 中提供了大量方法对集合元素进行排序.查询和修改等操作 ...

  10. linkin大话数据结构--Map

    Map 映射关系,也有人称为字典,Map集合里存在两组值,一组是key,一组是value.Map里的key不允许重复.通过key总能找到唯一的value与之对应.Map里的key集存储方式和对应的Se ...

随机推荐

  1. Mac appium.dmg. Xcode Command Line Tools

    You need to install the command line tools as marked in your message: ✖ Xcode Command Line Tools are ...

  2. navicat for sqlite 11.1.12 patch 永久试用 不报毒

    因为最近需要用这个但是网上都是注册机没有成功注册,所以就自己动手使用ollydbg开刀,    修改成了永久试用版本. 着急用所以没仔细分析,暂时先这样吧. 这个下载版本 http://dlsw.ba ...

  3. [转载]mysql绑定参数bind_param原理以及防SQL注入

    假设我们的用户表中存在一行.用户名字段为username.值为aaa.密码字段为pwd.值为pwd.. 下面我们来模拟一个用户登录的过程.. <?php $username = "aa ...

  4. Git学习随笔

    前期准备事项: 1.注册GitHub账号,注册地址:https://github.com 2.下载Git for Windows工具,下载地址:http://gitforwindows.org,软件安 ...

  5. HDFS中namenode启动失败

    1.环境配置: -1.core-site.xml文件 <configuration> <property> <name>fs.defaultFS</name& ...

  6. 深度解剖dubbo源码

    -----------学习dubbo源码,能给你带来什么好处?----------- 1.提升SOA的微服务架构设计能力   通过读dubbo源码是一条非常不错的通往SOA架构设计之路,毕竟SOA的服 ...

  7. python * 的区别

    >>> ['Spam']*5 ['Spam', 'Spam', 'Spam', 'Spam', 'Spam'] >>> ['Spam'*5] ['SpamSpamS ...

  8. ABP Zero示例项目问题总结

    1.ABP Zero项目,登录时出现如图“Empty or invalid anti forgery header token.”错误提示 ABP Zero项目,登录时出现如图“Empty or in ...

  9. [译]Dapper教程

    脑子里突然浮现出一个想法:尝试翻译一些技术文档.说干就干,先来翻译个最近经常查阅的Dapper教程,有兴趣的园友可以一起参与进来 dapper-tutorial-cn. 什么是Dapper Dappe ...

  10. 洛谷 P1598 垂直柱状图【字符串+模拟】

    P1598 垂直柱状图 题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. ...