HashSet类

HashSet集合底层是HashMap结构,HashMap底层是一个哈希散列表数据结构。
哈希表底层其实就是一个数组,只不过数组不像以前一样存放单个元素,而是数组每个元素是一条单向链表,每个单向链表都有一个独一无二的Hash值,代表数组的下标。在某个单向链表中的每个节点上的Hash值是相等的,hash值实际上是key调用的HashCode方法,在通过哈希算法转换成相应的值。
如何向哈希表中添加元素呢,或者说元素是通过怎样的判断被添加到链表中呢?首先添加元素时,会先调用key的HashCode方法,通过其返回的哈西码值,如果这个哈希表中不存在这个哈西码值,则直接将该元素添加,如果存在这个哈西码值,那么会调用equals方法判断该元素是否与某条链表的元素相同,如果返回值为false,则说明哈希表中没有该元素,就会添加该元素,返回值为true,放弃添加该元素。
我们可以通过重写HashCode方法与equals方法,让哈希表对元素的分类添加按照我们的要求来。
HashSet与HashMap初始化容量都是16,默认加载因子是0.75(当元素占总容量的75%时就会自动扩容!

 //入口public static void main(String[] args) {Set h1=new HashSet();//无序不可重复h1.add(1);h1.add("aa");h1.add(1);//遍历Iterator i=h1.iterator();while (i.hasNext()){System.out.println(i.next());}//关于往Set集合中存储的元素,该元素的hashCode方法与equals方法/*结论:存储在HashSet集合或者HashMap集合key部分的元素,需要同时重写hashCode与equals方法*///创建集合Set es=new HashSet();Employee e1=new Employee("1000","jack");Employee e2=new Employee("1000","jack");Employee e3=new Employee("3001","Scott");Employee e4=new Employee("4002","Clearlove");Employee e5=new Employee("5000","Faker");//因为再添加的过程中,e1与e2存储的员工编号与名字是相同的,按照业务逻辑,不应该被加入到集合当中,但是因为两个对象的不同,其哈希码就不同,所以会被添加,要重写hashCode方法System.out.println(e1.hashCode());System.out.println(e2.hashCode());//添加元素es.add(e1);es.add(e2);es.add(e3);es.add(e4);es.add(e5);//查看集合元素个数System.out.println(es.size());}
}
//根据现实的业务逻辑得知:该公司员工编号是:1000-9999
class   Employee{//编号String no;//姓名String name;//Constructorpublic Employee(String no, String name) {this.no = no;this.name = name;}//重写hashCode方法@Override//重写equals方法//如果员工编号相同,并且名字相同,则是同一个对象public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Employee e= (Employee) o;if(e.no.equals(this.no)&&e.name.equals(this.name)){return true;}return false;}@Override//重写hashCode方法public int hashCode() {//以员工编号分组return no.hashCode();}
}

LinkedHashSet类

LinkedHashSet类是HashSet类的子类,但是其数据结构与HashSet还是有区别的。
LinkedHashSet底层是有一个链表与一个哈希表,这个链表定义了迭代顺序,该顺序可以是插入的顺序或者是访问的顺序。
我们都清楚Set集合的特点:元素无序不可重复。无序性指的是我们添加元素时可能和取出集合元素的顺序不同。
但是这个集合就实现了有序。
 public static void main(String[] args) {HashSet s1=new HashSet();s1.add("a");s1.add(10);s1.add(5);s1.add("c");s1.add(2.0);s1.add("f");System.out.println(s1); //[2.0, a, c, 5, f, 10]System.out.println("==========");//按照什么顺序添加的,集合也就按照什么顺序排列HashSet s2=new LinkedHashSet();s2.add("a");s2.add(10);s2.add(5);s2.add("c");s2.add(2.0);s2.add("f");System.out.println(s2);//[a, 10, 5, c, 2.0, f]}

TreeSet类

TreeSet类实现了SortedSet接口,特点还是无序不可重复,但是存进去的元素可以按照元素大小顺序自动排列。
它的底层是SortedMap类。
 public static void main(String[] args) throws ParseException {//创建集合SortedSet ss=new TreeSet();//添加元素ss.add(15);//自动装箱,因为集合只能存储引用类型,所以,他会把基本类型转换为引用类型存储ss.add(20);ss.add(12);ss.add(1);//遍历集合Iterator it=ss.iterator();while (it.hasNext()){Object element=(Object)it.next();System.out.println(element);}/*1121520*/SortedSet ss1=new TreeSet();//添加日期元素String t1="2008-10-20";String t2="2000-05-8";SimpleDateFormat p=new SimpleDateFormat("yyyy-MM-dd");Date d1=p.parse(t1);Date d2=p.parse(t2);ss1.add(d1);ss1.add(d2);//遍历集合it=ss1.iterator();while (it.hasNext()){Object element=it.next();if (element instanceof Date){Date d=(Date)element;System.out.println(p.format(d));}/*2000-05-082008-10-20*/}}
我们已知它的底层是SortedMap结构,那它是如何实现排序的呢?
//录入学生成绩信息,并且将学生成绩按照大小排序将学生信息输出。public static void main(String[] args) {SortedSet<Students> stu=new TreeSet<>();System.out.println("请输入你要录入学生信息总数:");Scanner sc=new Scanner(System.in);Scanner sc1=new Scanner(System.in);int num=sc.nextInt();for (int i = 0; i <num; i++) {System.out.println("请输入学生姓名:");String stuName=sc.next();System.out.println("请输入学生总分:");float stuScore=sc1.nextInt();Students s=new Students(stuName,stuScore);stu.add(s);}for (Students s:stu) {System.out.println(s);}}
}
class Students{private String name;private float score;public Students (String name,float score){this.name=name;this.score=score;}@Overridepublic String toString() {return "学生姓名:" + name  + " 学生成绩:" + score ;}public float getScore(){return score;}
}
当我们使用将自定义对象存储到TreeSet集合中会出现一个异常:java.lang.ClassCastException: class Students cannot be cast to class java.lang.Comparable
叫做类型转换异常:学生类型不能被转换成可比较的类型。
那么为什么那些基本类型可以进行排序,自定义的数据类型就不可以?实际上基本类型底层实现了Comparable接口或者编写了一个Comparator比较器,用来比较元素进行排序。那我们如果要想自定义对象也进行排序,就有两种方法,一是学生类实现Comparable接口,二是单独编写一个比较器类实现Comparator接口,然后在创建TreeSet集合将比较器传入就行。
对于这两个方法我们只要取其一就可以,但是一般情况选择编写选择器比较好,因为程序设计原则就是面向接口,降低类与类之间的耦合度,编写比较器可以降低测试类与用户类的耦合度,所以优先选择。
实现接口,我们就要实现接口中的方法,虽然两个接口实现的方法不同,但是其思想是一样的。
class stuComparator implements Comparator{//用两个学生的成绩进行相减比较返回整形值@Overridepublic int compare(Object o, Object t1) {int num1= (int) (((Students)o).getScore()-((Students)t1).getScore());return num;}
}
这就是实现了Comparator接口的比较器,它底层采用了二叉树的思想进行排序,两个元素进行相减比较,然后返回一个整形的值,底层会用返回的整形值进行判断,当返回值为0的时候那就表明这两个值是相等的,返回值大于0,就将它往二叉树的元素右边排,返回值小于0,往左边排,这样就实现了元素的排序。
那么这下我们将比较器传入,就能排好序啦!
public static void main(String[] args) {SortedSet<Students> stu=new TreeSet<>(new stuComparator());//传入比较器System.out.println("请输入你要录入学生信息总数:");Scanner sc=new Scanner(System.in);Scanner sc1=new Scanner(System.in);int num=sc.nextInt();for (int i = 0; i <num; i++) {System.out.println("请输入学生姓名:");String stuName=sc.next();System.out.println("请输入学生总分:");float stuScore=sc1.nextInt();Students s=new Students(stuName,stuScore);stu.add(s);}for (Students s:stu) {System.out.println(s);}/*学生姓名:aa 学生成绩:500.0学生姓名:cc 学生成绩:400.0学生姓名:bb 学生成绩:300.0*/}

Set接口下的三个实用类相关推荐

  1. Jmeter+ant实现接口自动化(三)

    1.来看看jmeter生成自带的测试报告 进入jmeter的解压路径下的/bin,执行某个路径下的jmx文件: jmeter -n -t /Users/ss/Desktop/jmeter/参数化.jm ...

  2. 基于FPGA的VGA接口设计(三)

    关于VGA系列文章的所有链接: 基于FPGA的VGA接口设计(一) 基于FPGA的VGA接口设计(二) 基于FPGA的VGA接口设计(三) 结篇   在之前的文章中介绍了有关VGA的扫描方式.行场同步 ...

  3. 火山PC抓取快递物流查询接口教程第三课

    本源码转载自利快云https://www.lkuaiy.com/ 火山PC抓取快递物流查询接口教程第三课 一.本课目标 本节以网页公开快递查询网站(http://www.kuaidi.com)进行教学 ...

  4. 微型计算机原理与接口技术 第三版(张荣标)答案

    微型计算机原理与接口技术第三版答案 第1章 练习题 1.选择题 (1)B C A (2) A (3) D A (4) C 2.填空 (1) 10, 12 (2) 取出指令, 执行指令 (3) (4) ...

  5. java 获取所有实现类_Java动态获取实现某个接口下所有的实现类对象集合

    Java动态获取实现某个接口下所有的实现类对象集合 最近有个需求,我需要获取所有同一类型的定时任务的对象,并自动执行. 我想的方案是:直接获取某个接口下面所有的实现类的对象集合,方便以后只需要 实现这 ...

  6. Qt在Windows下的三种编程环境搭建

    未经验证,记录在此. 尊重作者,支持原创,如需转载,请附上原地址:http://blog.csdn.net/libaineu2004/article/details/17363165 从QT官网可以得 ...

  7. Java代码示例: 使用reflections工具类获取某接口下所有的实现类

    pom依赖 <dependency><groupId>org.reflections</groupId><artifactId>reflections& ...

  8. [css] 说下line-height三种赋值方式有何区别?

    [css] 说下line-height三种赋值方式有何区别? line-height 可以有带单位及不带单位的写法(感觉其实是两种).div{line-height: 24px;line-height ...

  9. 好久没玩laravel了,5.6玩下(三)

    好久没玩laravel了,5.6玩下(三) 好了,基础的测试通了,咱们开始增删改了 思路整理 先创建项目功能控制器 然后设置路由访问规则 然后开发项目的增删改功能 1 先创建项目的控制器 php ar ...

最新文章

  1. Taglib原理和实现:再论El和JST
  2. 深度学习中 Embedding层两大作用的个人理解
  3. zabbix企业应用之low level discovery监控磁盘吞吐量与iops
  4. SQL on Linux Run on Docker
  5. VMware中无法识别usb
  6. c++学习笔记之多文件操作
  7. html5 将资源存于客户端,HTML5离线应用与客户端存储的实现
  8. freemodbus源码/获取地址
  9. 外圆内方与外方内圆的奇妙变换!
  10. Jupyter 安装使用
  11. Android代码混淆方法,Android 代码混淆零基础入门
  12. python天气查询系统有什么知识点_Python入门 天气查询程序
  13. 函数——C++的编程模块
  14. 中国计算机学会推荐国际学术会议和期刊目录(2019)
  15. arcMap安装教程
  16. xlsx xlsx-style 设置导出的exce表格样式
  17. 如何构建自己的游戏框架并且制作游戏(一)(附源码)
  18. vs2015安装与配置
  19. 淘宝价格带卡位公式是什么?如何定价?
  20. cocos2dx ipv6处理

热门文章

  1. php 2038,php在2038年后datetime类也无法获得当前日期的解决
  2. 万能遥控程序c语言,51单片机万能红外遥控解码程序
  3. 光纤设备及跳线接口图鉴
  4. Sikerio --《只狼》
  5. 众里寻他千百度:找网红算法
  6. 正则表达式中(RegExp)的字符和转译
  7. 王家族字辈(我的家族字辈)
  8. Linux系统编程笔记(李慧琴) 2
  9. 一个 JDBC 实现对 mysql 进行分页查询的 实例
  10. python写excel标记文字颜色_[知识积累]python3使用xlwt时写入文档字体颜色和边框样式--转载...